Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
 into release-1.0.0
  • Loading branch information
TwitchBronBron committed Jan 16, 2025
2 parents 1a27f76 + 71f9feb commit 4d932f3
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 22 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.66.0-alpha.0](https://github.com/rokucommunity/brighterscript/compare/v0.65.1...v0.66.0-alpha.0) - 2023-06-09
### Changed
- all the type tracking stuff!
## [0.68.3](https://github.com/rokucommunity/brighterscript/compare/v0.68.2...v0.68.3) - 2025-01-13
### Changed
- Export more items ([#1394](https://github.com/rokucommunity/brighterscript/pull/1394))
### Fixed
- Fix class transpile issue with child class constructor not inherriting parent params ([#1390](https://github.com/rokucommunity/brighterscript/pull/1390))



## [0.68.2](https://github.com/rokucommunity/brighterscript/compare/v0.68.1...v0.68.2) - 2024-12-06
### Changed
- Add more convenience exports from vscode-languageserver ([#1359](https://github.com/rokucommunity/brighterscript/pull/1359))
Expand Down
99 changes: 86 additions & 13 deletions src/files/BrsFile.Class.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ describe('BrsFile BrighterScript classes', () => {
`, undefined, 'source/main.bs');
});

it('works for simple class', async () => {
it('works for simple class', async () => {
await testTranspile(`
class Duck
end class
Expand All @@ -475,6 +475,79 @@ describe('BrsFile BrighterScript classes', () => {
`, undefined, 'source/main.bs');
});

it('inherits the parameters of the last known constructor', async () => {
await testTranspile(`
class Animal
sub new(p1)
end sub
end class
class Bird extends Animal
end class
class Duck extends Bird
sub new(p1, p2)
super(p1)
m.p2 = p2
end sub
private p2 as dynamic
end class
class BabyDuck extends Duck
end class
`, `
function __Animal_builder()
instance = {}
instance.new = sub(p1)
end sub
return instance
end function
function Animal(p1)
instance = __Animal_builder()
instance.new(p1)
return instance
end function
function __Bird_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
instance.new = sub(p1)
m.super0_new(p1)
end sub
return instance
end function
function Bird(p1)
instance = __Bird_builder()
instance.new(p1)
return instance
end function
function __Duck_builder()
instance = __Bird_builder()
instance.super1_new = instance.new
instance.new = sub(p1, p2)
m.super1_new(p1)
m.p2 = invalid
m.p2 = p2
end sub
return instance
end function
function Duck(p1, p2)
instance = __Duck_builder()
instance.new(p1, p2)
return instance
end function
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super2_new = instance.new
instance.new = sub(p1, p2)
m.super2_new(p1, p2)
end sub
return instance
end function
function BabyDuck(p1, p2)
instance = __BabyDuck_builder()
instance.new(p1, p2)
return instance
end function
`);
});

it('registers the constructor and properly handles its parameters', async () => {
await testTranspile(`
class Duck
Expand Down Expand Up @@ -579,8 +652,8 @@ describe('BrsFile BrighterScript classes', () => {
function __Duck_builder()
instance = __Creature_builder()
instance.super0_new = instance.new
instance.new = sub()
m.super0_new()
instance.new = sub(name as string)
m.super0_new(name)
end sub
instance.super0_sayHello = instance.sayHello
instance.sayHello = function(text)
Expand All @@ -591,9 +664,9 @@ describe('BrsFile BrighterScript classes', () => {
end function
return instance
end function
function Duck()
function Duck(name as string)
instance = __Duck_builder()
instance.new()
instance.new(name)
return instance
end function
`, 'trim', 'source/main.bs'
Expand Down Expand Up @@ -784,8 +857,8 @@ describe('BrsFile BrighterScript classes', () => {
function __Duck_builder()
instance = __Animal_builder()
instance.super0_new = instance.new
instance.new = sub()
m.super0_new()
instance.new = sub(name as string)
m.super0_new(name)
end sub
instance.super0_move = instance.move
instance.move = sub(distanceInMeters as integer)
Expand All @@ -794,16 +867,16 @@ describe('BrsFile BrighterScript classes', () => {
end sub
return instance
end function
function Duck()
function Duck(name as string)
instance = __Duck_builder()
instance.new()
instance.new(name)
return instance
end function
function __BabyDuck_builder()
instance = __Duck_builder()
instance.super1_new = instance.new
instance.new = sub()
m.super1_new()
instance.new = sub(name as string)
m.super1_new(name)
end sub
instance.super1_move = instance.move
instance.move = sub(distanceInMeters as integer)
Expand All @@ -812,9 +885,9 @@ describe('BrsFile BrighterScript classes', () => {
end sub
return instance
end function
function BabyDuck()
function BabyDuck(name as string)
instance = __BabyDuck_builder()
instance.new()
instance.new(name)
return instance
end function
Expand Down
72 changes: 63 additions & 9 deletions src/parser/Statement.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable no-bitwise */
import type { Token, Identifier } from '../lexer/Token';
import { TokenKind } from '../lexer/TokenKind';
import type { DottedGetExpression, FunctionExpression, FunctionParameterExpression, LiteralExpression, TypeExpression, TypecastExpression } from './Expression';
import type { DottedGetExpression, FunctionParameterExpression, LiteralExpression, TypecastExpression, TypeExpression } from './Expression';
import { FunctionExpression } from './Expression';
import { CallExpression, VariableExpression } from './Expression';
import { util } from '../util';
import type { Location } from 'vscode-languageserver';
Expand All @@ -10,8 +11,9 @@ import { ParseMode } from './Parser';
import type { WalkVisitor, WalkOptions } from '../astUtils/visitors';
import { InternalWalkMode, walk, createVisitor, WalkMode, walkArray } from '../astUtils/visitors';
import { isCallExpression, isCatchStatement, isConditionalCompileStatement, isEnumMemberStatement, isExpressionStatement, isFieldStatement, isForEachStatement, isForStatement, isFunctionExpression, isFunctionStatement, isIfStatement, isInterfaceFieldStatement, isInterfaceMethodStatement, isInvalidType, isLiteralExpression, isMethodStatement, isNamespaceStatement, isPrintSeparatorExpression, isTryCatchStatement, isTypedefProvider, isUnaryExpression, isUninitializedType, isVoidType, isWhileStatement } from '../astUtils/reflection';
import { TypeChainEntry, type GetTypeOptions, type TranspileResult, type TypedefProvider } from '../interfaces';
import { createInvalidLiteral, createMethodStatement, createToken } from '../astUtils/creators';
import type { GetTypeOptions } from '../interfaces';
import { TypeChainEntry, type TranspileResult, type TypedefProvider } from '../interfaces';
import { createIdentifier, createInvalidLiteral, createMethodStatement, createToken } from '../astUtils/creators';
import { DynamicType } from '../types/DynamicType';
import type { BscType } from '../types/BscType';
import { SymbolTable } from '../SymbolTable';
Expand Down Expand Up @@ -2781,7 +2783,7 @@ export class ClassStatement extends Statement implements TypedefProvider {
let stmt = this as ClassStatement;
while (stmt) {
if (stmt.parentClassName) {
const namespace = this.findAncestor<NamespaceStatement>(isNamespaceStatement);
const namespace = stmt.findAncestor<NamespaceStatement>(isNamespaceStatement);
stmt = state.file.getClassFileLink(
stmt.parentClassName.getName(),
namespace?.getName(ParseMode.BrighterScript)
Expand Down Expand Up @@ -2816,6 +2818,21 @@ export class ClassStatement extends Statement implements TypedefProvider {
}) as MethodStatement;
}

/**
* Return the parameters for the first constructor function for this class
* @param ancestors The list of ancestors for this class
* @returns The parameters for the first constructor function for this class
*/
private getConstructorParams(ancestors: ClassStatement[]) {
for (let ancestor of ancestors) {
const ctor = ancestor?.getConstructorFunction();
if (ctor) {
return ctor.func.parameters;
}
}
return [];
}

/**
* Determine if the specified field was declared in one of the ancestor classes
*/
Expand Down Expand Up @@ -2869,10 +2886,42 @@ export class ClassStatement extends Statement implements TypedefProvider {
let body = this.body;
//inject an empty "new" method if missing
if (!this.getConstructorFunction()) {
body = [
createMethodStatement('new', TokenKind.Sub),
...this.body
];
if (ancestors.length === 0) {
body = [
createMethodStatement('new', TokenKind.Sub),
...this.body
];
} else {
const params = this.getConstructorParams(ancestors);
const call = new ExpressionStatement({
expression: new CallExpression({
callee: new VariableExpression({
name: createToken(TokenKind.Identifier, 'super')
}),
openingParen: createToken(TokenKind.LeftParen),
args: params.map(x => new VariableExpression({
name: util.cloneToken(x.tokens.name)
})),
closingParen: createToken(TokenKind.RightParen)
})
});
body = [
new MethodStatement({
name: createIdentifier('new'),
func: new FunctionExpression({
parameters: params.map(x => x.clone()),
body: new Block({
statements: [call]
}),
functionType: createToken(TokenKind.Sub),
endFunctionType: createToken(TokenKind.EndSub),
leftParen: createToken(TokenKind.LeftParen),
rightParen: createToken(TokenKind.RightParen)
})
}),
...this.body
];
}
}

for (let statement of body) {
Expand Down Expand Up @@ -2942,7 +2991,12 @@ export class ClassStatement extends Statement implements TypedefProvider {
private getTranspiledClassFunction(state: BrsTranspileState) {
let result: TranspileResult = state.transpileAnnotations(this);
const constructorFunction = this.getConstructorFunction();
const constructorParams = constructorFunction ? constructorFunction.func.parameters : [];
let constructorParams = [];
if (constructorFunction) {
constructorParams = constructorFunction.func.parameters;
} else {
constructorParams = this.getConstructorParams(this.getAncestors(state));
}

result.push(
state.transpileLeadingComments(this.tokens.class),
Expand Down

0 comments on commit 4d932f3

Please sign in to comment.