brighterscript
Advanced tools
Comparing version 0.16.5 to 0.16.6
@@ -9,2 +9,8 @@ # Changelog | ||
## [0.16.6] - 2020-10-13 | ||
### Fixed | ||
- quirk in the GitHub actions workflow that didn't publish the correct code. | ||
## [0.16.5] - 2020-10-13 | ||
@@ -609,1 +615,2 @@ ### Fixed | ||
[0.16.5]: https://github.com/rokucommunity/brighterscript/compare/v0.16.4...v0.16.5 | ||
[0.16.6]: https://github.com/rokucommunity/brighterscript/compare/v0.16.5...v0.16.6 |
@@ -515,3 +515,3 @@ import { DiagnosticSeverity, Position } from 'vscode-languageserver'; | ||
}; | ||
classConstructorSuperMustBeFirstStatement: () => { | ||
classConstructorIllegalUseOfMBeforeSuperCall: () => { | ||
message: string; | ||
@@ -518,0 +518,0 @@ code: number; |
@@ -523,4 +523,4 @@ "use strict"; | ||
}), | ||
classConstructorSuperMustBeFirstStatement: () => ({ | ||
message: `A call to 'super()' must be the first statement in this constructor method.`, | ||
classConstructorIllegalUseOfMBeforeSuperCall: () => ({ | ||
message: `Illegal use of "m" before calling "super()"`, | ||
code: 1101, | ||
@@ -527,0 +527,0 @@ severity: vscode_languageserver_1.DiagnosticSeverity.Error |
@@ -99,2 +99,73 @@ "use strict"; | ||
}); | ||
describe('super', () => { | ||
it('always requires super call in child constructor', async () => { | ||
var _a; | ||
await program.addOrReplaceFile('source/main.bs', ` | ||
class Bird | ||
end class | ||
class Duck extends Bird | ||
sub new() | ||
end sub | ||
end class | ||
`); | ||
await program.validate(); | ||
chai_1.expect((_a = program.getDiagnostics()[0]) === null || _a === void 0 ? void 0 : _a.message).to.eql(DiagnosticMessages_1.DiagnosticMessages.classConstructorMissingSuperCall().message); | ||
}); | ||
it('requires super call in child when parent has own `new` method', async () => { | ||
var _a; | ||
await program.addOrReplaceFile('source/main.bs', ` | ||
class Bird | ||
sub new() | ||
end sub | ||
end class | ||
class Duck extends Bird | ||
sub new() | ||
end sub | ||
end class | ||
`); | ||
await program.validate(); | ||
chai_1.expect((_a = program.getDiagnostics()[0]) === null || _a === void 0 ? void 0 : _a.message).to.eql(DiagnosticMessages_1.DiagnosticMessages.classConstructorMissingSuperCall().message); | ||
}); | ||
it('allows non-`m` expressions and statements before the super call', async () => { | ||
var _a; | ||
await program.addOrReplaceFile('source/main.bs', ` | ||
class Bird | ||
sub new(name) | ||
end sub | ||
end class | ||
class Duck extends Bird | ||
sub new() | ||
thing = { m: "m"} | ||
print thing.m | ||
name = "Donald" + "Duck" | ||
super(name) | ||
end sub | ||
end class | ||
`); | ||
await program.validate(); | ||
chai_1.expect((_a = program.getDiagnostics()[0]) === null || _a === void 0 ? void 0 : _a.message).to.be.undefined; | ||
}); | ||
it('allows non-`m` expressions and statements before the super call', async () => { | ||
await program.addOrReplaceFile('source/main.bs', ` | ||
class Bird | ||
sub new(name) | ||
end sub | ||
end class | ||
class Duck extends Bird | ||
sub new() | ||
m.name = m.name + "Duck" | ||
super() | ||
end sub | ||
end class | ||
`); | ||
await program.validate(); | ||
chai_1.expect(program.getDiagnostics().map(x => ({ message: x.message, range: x.range }))).to.eql([{ | ||
message: DiagnosticMessages_1.DiagnosticMessages.classConstructorIllegalUseOfMBeforeSuperCall().message, | ||
range: vscode_languageserver_1.Range.create(7, 24, 7, 25) | ||
}, { | ||
message: DiagnosticMessages_1.DiagnosticMessages.classConstructorIllegalUseOfMBeforeSuperCall().message, | ||
range: vscode_languageserver_1.Range.create(7, 33, 7, 34) | ||
}]); | ||
}); | ||
}); | ||
describe('transpile', () => { | ||
@@ -101,0 +172,0 @@ it('follows correct sequence for property initializers', async () => { |
@@ -460,3 +460,8 @@ "use strict"; | ||
for (let expCall of file.functionCalls) { | ||
let lowerName = expCall.name.toLowerCase(); | ||
const lowerName = expCall.name.toLowerCase(); | ||
//for now, skip validation on any method named "super" within `.bs` contexts. | ||
//TODO revise this logic so we know if this function call resides within a class constructor function | ||
if (file.extension === '.bs' && lowerName === 'super') { | ||
continue; | ||
} | ||
//get the local scope for this expression | ||
@@ -463,0 +468,0 @@ let scope = file.getFunctionScopeAtPosition(expCall.nameRange.start); |
@@ -10,2 +10,3 @@ "use strict"; | ||
const reflection_1 = require("../astUtils/reflection"); | ||
const astUtils_1 = require("../astUtils"); | ||
class BsClassValidator { | ||
@@ -78,7 +79,5 @@ validate(scope) { | ||
verifyChildConstructor() { | ||
var _a, _b, _c; | ||
for (let key in this.classes) { | ||
let classStatement = this.classes[key]; | ||
let newMethod = classStatement.memberMap.new; | ||
let ancestorNewMethod = this.getAncestorMember(classStatement, 'new'); | ||
const newMethod = classStatement.memberMap.new; | ||
if ( | ||
@@ -88,19 +87,27 @@ //this class has a "new method" | ||
//this class has a parent class | ||
classStatement.parentClass && | ||
//this class's ancestors have a "new" method | ||
ancestorNewMethod) { | ||
//verify there's a `super()` as the first statement in this member's "new" method | ||
let firstStatement = (_c = (_b = (_a = newMethod.func) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.statements[0]) === null || _c === void 0 ? void 0 : _c.expression; | ||
//if the first statement isn't a call | ||
if (reflection_1.isCallExpression(firstStatement) === false) { | ||
classStatement.parentClass) { | ||
//prevent use of `m.` anywhere before the `super()` call | ||
const cancellationToken = new vscode_languageserver_1.CancellationTokenSource(); | ||
let superCall; | ||
newMethod.func.body.walk(astUtils_1.createVisitor({ | ||
VariableExpression: (expression, parent) => { | ||
var _a; | ||
const expressionNameLower = (_a = expression === null || expression === void 0 ? void 0 : expression.name) === null || _a === void 0 ? void 0 : _a.text.toLowerCase(); | ||
if (expressionNameLower === 'm') { | ||
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classConstructorIllegalUseOfMBeforeSuperCall()), { file: classStatement.file, range: expression.range })); | ||
} | ||
if (reflection_1.isCallExpression(parent) && expressionNameLower === 'super') { | ||
superCall = parent; | ||
//stop walking | ||
cancellationToken.cancel(); | ||
} | ||
} | ||
}), { | ||
walkMode: astUtils_1.WalkMode.visitAll, | ||
cancel: cancellationToken.token | ||
}); | ||
//every child class constructor must include a call to `super()` | ||
if (!superCall) { | ||
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classConstructorMissingSuperCall()), { file: classStatement.file, range: newMethod.range })); | ||
//if the first statement's left-hand-side callee isn't a variable | ||
} | ||
else if (reflection_1.isVariableExpression(firstStatement.callee) === false) { | ||
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classConstructorSuperMustBeFirstStatement()), { file: classStatement.file, range: firstStatement.range })); | ||
//if the method is not called "super" | ||
} | ||
else if (firstStatement.callee.name.text.toLowerCase() !== 'super') { | ||
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classConstructorSuperMustBeFirstStatement()), { file: classStatement.file, range: firstStatement.range })); | ||
} | ||
} | ||
@@ -107,0 +114,0 @@ } |
{ | ||
"name": "brighterscript", | ||
"version": "0.16.5", | ||
"version": "0.16.6", | ||
"description": "A superset of Roku's BrightScript language.", | ||
@@ -5,0 +5,0 @@ "scripts": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
2454230
34934