More tests and fixes (unary, binary, globals)

This commit is contained in:
dcodeIO
2017-12-02 18:37:59 +01:00
parent ef859937a8
commit b9edfb5185
22 changed files with 2159 additions and 80 deletions

View File

@ -925,12 +925,13 @@ export abstract class Statement extends Node {
return stmt;
}
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, range: Range): VariableDeclaration {
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, range: Range): VariableDeclaration {
const elem: VariableDeclaration = new VariableDeclaration();
elem.range = range;
(elem.identifier = identifier).parent = elem;
if (elem.type = type) (<TypeNode>type).parent = elem;
if (elem.initializer = initializer) (<Expression>initializer).parent = elem;
elem.modifiers = modifiers;
return elem;
}
@ -1681,7 +1682,7 @@ export class TryStatement extends Statement {
export class VariableDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.VARIABLEDECLARATION;
modifiers = null;
modifiers: Modifier[] | null;
serialize(sb: string[]): void {
this.identifier.serialize(sb);

View File

@ -90,6 +90,15 @@ export class Options {
noTreeShaking: bool = false;
}
const enum ConversionKind {
/** No conversion. */
NONE,
/** Implicit conversion. */
IMPLICIT,
/** Explicit conversion. */
EXPLICIT
}
export class Compiler extends DiagnosticEmitter {
/** Program reference. */
@ -141,7 +150,7 @@ export class Compiler extends DiagnosticEmitter {
compile(): Module {
const program: Program = this.program;
// initialize lookup maps
// initialize lookup maps, builtins, imports, exports, etc.
program.initialize(this.options.target);
// compile entry file (exactly one, usually)
@ -181,7 +190,7 @@ export class Compiler extends DiagnosticEmitter {
heapStartBuffer[7] = (initial.hi >>> 24) as u8;
} else {
if (!initial.fitsInU32)
throw new Error("memory size overflow");
throw new Error("static memory size overflows 32 bits");
heapStartBuffer = new Uint8Array(4);
heapStartOffset = 4;
heapStartBuffer[0] = (initial.lo ) as u8;
@ -299,6 +308,8 @@ export class Compiler extends DiagnosticEmitter {
return false;
element.type = type;
}
if (this.module.noEmit)
return true;
const nativeType: NativeType = typeToNativeType(<Type>type);
let initializer: ExpressionRef;
let initializeInStart: bool;
@ -331,10 +342,10 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected missing declaration or constant value");
const internalName: string = element.internalName;
if (initializeInStart) {
this.module.addGlobal(internalName, NativeType.I32, true, this.module.createI32(-1));
this.module.addGlobal(internalName, nativeType, true, this.module.createI32(-1));
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
} else
this.module.addGlobal(internalName, NativeType.I32, element.isMutable, initializer);
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
return element.isCompiled = true;
}
@ -350,7 +361,6 @@ export class Compiler extends DiagnosticEmitter {
compileEnum(element: Enum): void {
if (element.isCompiled)
return;
element.isCompiled = true;
let previousInternalName: string | null = null;
for (let [key, val] of element.members) {
if (val.hasConstantValue) {
@ -381,6 +391,7 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected missing declaration or constant value");
previousInternalName = val.internalName;
}
element.isCompiled = true;
}
// functions
@ -405,8 +416,8 @@ export class Compiler extends DiagnosticEmitter {
return;
const declaration: FunctionDeclaration | null = instance.template.declaration;
if (!declaration) // TODO: compile builtins
throw new Error("not implemented");
if (!declaration)
throw new Error("unexpected missing declaration");
if (!declaration.statements) {
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, declaration.identifier.range);
@ -588,7 +599,7 @@ export class Compiler extends DiagnosticEmitter {
const previousType: Type = this.currentType;
const previousNoEmit: bool = this.module.noEmit;
this.module.noEmit = true;
this.compileExpression(expression, contextualType, false); // now performs a dry run
this.compileExpression(expression, contextualType, ConversionKind.NONE); // now performs a dry run
const type: Type = this.currentType;
this.currentType = previousType;
this.module.noEmit = previousNoEmit;
@ -698,7 +709,12 @@ export class Compiler extends DiagnosticEmitter {
}
compileExpressionStatement(statement: ExpressionStatement): ExpressionRef {
return this.compileExpression(statement.expression, Type.void);
let expr: ExpressionRef = this.compileExpression(statement.expression, Type.void, ConversionKind.NONE);
if (this.currentType != Type.void) {
expr = this.module.createDrop(expr);
this.currentType = Type.void;
}
return expr;
}
compileForStatement(statement: ForStatement): ExpressionRef {
@ -850,7 +866,7 @@ export class Compiler extends DiagnosticEmitter {
// expressions
compileExpression(expression: Expression, contextualType: Type, convert: bool = true): ExpressionRef {
compileExpression(expression: Expression, contextualType: Type, conversionKind: ConversionKind = ConversionKind.IMPLICIT): ExpressionRef {
this.currentType = contextualType;
let expr: ExpressionRef;
@ -912,19 +928,22 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected expression kind");
}
if (convert && this.currentType != contextualType) {
expr = this.convertExpression(expr, this.currentType, contextualType);
if (conversionKind != ConversionKind.NONE) {
expr = this.convertExpression(expr, this.currentType, contextualType, conversionKind, expression);
this.currentType = contextualType;
}
return expr;
}
convertExpression(expr: ExpressionRef, fromType: Type, toType: Type): ExpressionRef {
convertExpression(expr: ExpressionRef, fromType: Type, toType: Type, conversionKind: ConversionKind, reportNode: Node): ExpressionRef {
if (conversionKind == ConversionKind.NONE)
return expr;
// void to any
if (fromType.kind == TypeKind.VOID)
if (fromType.kind == TypeKind.VOID) {
this.error(DiagnosticCode.Operation_not_supported, reportNode.range);
throw new Error("unexpected conversion from void");
}
// any to void
if (toType.kind == TypeKind.VOID)
@ -1070,16 +1089,17 @@ export class Compiler extends DiagnosticEmitter {
}
}
if (losesInformation && conversionKind == ConversionKind.IMPLICIT)
this.error(DiagnosticCode.Conversion_from_type_0_to_1_requires_an_explicit_cast, reportNode.range, fromType.toString(), toType.toString());
return expr;
}
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (toType && toType != contextualType) {
const expr: ExpressionRef = this.compileExpression(expression.expression, <Type>toType, false);
return this.convertExpression(expr, this.currentType, <Type>toType);
}
return this.compileExpression(expression.expression, contextualType);
return toType && toType != contextualType
? this.compileExpression(expression.expression, <Type>toType, ConversionKind.EXPLICIT)
: this.compileExpression(expression.expression, contextualType);
}
compileBinaryExpression(expression: BinaryExpression, contextualType: Type): ExpressionRef {
@ -1091,7 +1111,7 @@ export class Compiler extends DiagnosticEmitter {
switch (expression.operator) {
case Token.LESSTHAN:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.LtF32
@ -1104,7 +1124,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.GREATERTHAN:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.GtF32
@ -1117,7 +1137,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.LESSTHAN_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.LeF32
@ -1130,7 +1150,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.GREATERTHAN_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.GeF32
@ -1144,7 +1164,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.EQUALS_EQUALS:
case Token.EQUALS_EQUALS_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.EqF32
@ -1162,7 +1182,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.PLUS_EQUALS:
compound = Token.EQUALS;
case Token.PLUS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.AddF32
@ -1176,7 +1196,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.MINUS_EQUALS:
compound = Token.EQUALS;
case Token.MINUS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.SubF32
@ -1190,7 +1210,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.ASTERISK_EQUALS:
compound = Token.EQUALS;
case Token.ASTERISK:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.MulF32
@ -1204,7 +1224,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.SLASH_EQUALS:
compound = Token.EQUALS;
case Token.SLASH:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.DivF32
@ -1218,7 +1238,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.PERCENT_EQUALS:
compound = Token.EQUALS;
case Token.PERCENT:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
if (this.currentType.isAnyFloat)
throw new Error("not implemented"); // TODO: internal fmod, possibly simply imported from JS
@ -1230,7 +1250,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.LESSTHAN_LESSTHAN_EQUALS:
compound = Token.EQUALS;
case Token.LESSTHAN_LESSTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.ShlI64
@ -1240,7 +1260,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.GREATERTHAN_GREATERTHAN_EQUALS:
compound = Token.EQUALS;
case Token.GREATERTHAN_GREATERTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isSignedInteger
? this.currentType.isLongInteger
@ -1254,7 +1274,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS:
compound = Token.EQUALS;
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.u64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.u64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.ShrU64
@ -1264,7 +1284,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.AMPERSAND_EQUALS:
compound = Token.EQUALS;
case Token.AMPERSAND:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.AndI64
@ -1274,7 +1294,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.BAR_EQUALS:
compound = Token.EQUALS;
case Token.BAR:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.OrI64
@ -1284,7 +1304,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.CARET_EQUALS:
compound = Token.EQUALS;
case Token.CARET:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.XorI64
@ -1316,11 +1336,17 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = (<Local>element).type;
return this.module.createTeeLocal((<Local>element).index, valueWithCorrectType);
}
this.currentType = Type.void;
return this.module.createSetLocal((<Local>element).index, valueWithCorrectType);
}
if (element.kind == ElementKind.GLOBAL && (<Global>element).type) {
if (element.kind == ElementKind.GLOBAL) {
this.compileGlobal(<Global>element);
if (!(<Global>element).isMutable)
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, element.internalName);
if (tee) {
if (!(<Global>element).type)
return this.module.createUnreachable();
const globalNativeType: NativeType = typeToNativeType(<Type>(<Global>element).type);
this.currentType = <Type>(<Global>element).type;
return this.module.createBlock(null, [ // teeGlobal
@ -1328,6 +1354,7 @@ export class Compiler extends DiagnosticEmitter {
this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
], globalNativeType);
}
this.currentType = Type.void;
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
}
@ -1384,7 +1411,7 @@ export class Compiler extends DiagnosticEmitter {
const operands: ExpressionRef[] = new Array(parameterCount);
for (let i: i32 = 0; i < parameterCount; ++i) {
if (argumentExpressions.length > i) {
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type, true);
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type);
} else {
const initializer: Expression | null = parameters[i].initializer;
if (initializer) { // omitted, uses initializer
@ -1621,47 +1648,52 @@ export class Compiler extends DiagnosticEmitter {
} else if (expression.kind == NodeKind.THIS) {
if (this.currentFunction.instanceMethodOf) {
this.currentType = this.currentFunction.instanceMethodOf.type;
return this.module.createGetLocal(0, typeToNativeType(this.currentType));
return this.module.createGetLocal(0, this.options.target == Target.WASM64 ? NativeType.I64 : NativeType.I32);
}
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
return this.module.createUnreachable();
}
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
if (!element) {
if (expression.kind == NodeKind.IDENTIFIER) {
if (expression.kind == NodeKind.IDENTIFIER) {
// NaN
if ((<IdentifierExpression>expression).name == "NaN")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(NaN);
else {
this.currentType = Type.f64;
return this.module.createF64(NaN);
}
// NaN
if ((<IdentifierExpression>expression).name == "NaN")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(NaN);
else {
this.currentType = Type.f64;
return this.module.createF64(NaN);
}
// Infinity
if ((<IdentifierExpression>expression).name == "Infinity")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(Infinity);
else {
this.currentType = Type.f64;
return this.module.createF64(Infinity);
}
}
return this.module.createUnreachable();
// Infinity
if ((<IdentifierExpression>expression).name == "Infinity")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(Infinity);
else {
this.currentType = Type.f64;
return this.module.createF64(Infinity);
}
}
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
if (!element)
return this.module.createUnreachable();
// local
if (element.kind == ElementKind.LOCAL)
if (element.kind == ElementKind.LOCAL) {
this.currentType = (<Local>element).type;
return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType = (<Local>element).type));
}
// global
if (element.kind == ElementKind.GLOBAL)
if (element.kind == ElementKind.GLOBAL) {
if ((<Global>element).type)
this.currentType = <Type>(<Global>element).type;
return this.compileGlobal(<Global>element) // reports
? this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType = <Type>(<Global>element).type))
: this.module.createUnreachable();
}
// field
// if (element.kind == ElementKind.FIELD)
@ -1691,6 +1723,10 @@ export class Compiler extends DiagnosticEmitter {
const intValue: I64 = (<IntegerLiteralExpression>expression).value;
if (contextualType == Type.bool && (intValue.isZero || intValue.isOne))
return this.module.createI32(intValue.isZero ? 0 : 1);
if (contextualType == Type.f64)
return this.module.createF64((<f64>intValue.lo) + (<f64>intValue.hi) * 0xffffffff);
if (contextualType == Type.f32)
return this.module.createF32((<f32>intValue.lo) + (<f32>intValue.hi) * 0xffffffff);
if (contextualType.isLongInteger)
return this.module.createI64(intValue.lo, intValue.hi);
if (!intValue.fitsInI32) {
@ -1769,10 +1805,10 @@ export class Compiler extends DiagnosticEmitter {
switch (expression.operator) {
case Token.PLUS:
return this.compileExpression(operandExpression, contextualType);
return this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
case Token.MINUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
if (this.currentType == Type.f32)
op = UnaryOp.NegF32;
else if (this.currentType == Type.f64)
@ -1784,7 +1820,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.PLUS_PLUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType == Type.f32
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddF32, operand, this.module.createF32(1)), contextualType != Type.void)
: this.currentType == Type.f64
@ -1794,7 +1830,7 @@ export class Compiler extends DiagnosticEmitter {
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddI32, operand, this.module.createI32(1)), contextualType != Type.void);
case Token.MINUS_MINUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType == Type.f32
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubF32, operand, this.module.createF32(1)), contextualType != Type.void)
: this.currentType == Type.f64
@ -1804,7 +1840,7 @@ export class Compiler extends DiagnosticEmitter {
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubI32, operand, this.module.createI32(1)), contextualType != Type.void);
case Token.EXCLAMATION:
operand = this.compileExpression(operandExpression, Type.bool, false);
operand = this.compileExpression(operandExpression, Type.bool, ConversionKind.NONE);
if (this.currentType == Type.f32) {
this.currentType = Type.bool;
return this.module.createBinary(BinaryOp.EqF32, operand, this.module.createF32(0));
@ -1820,7 +1856,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.TILDE:
operand = this.compileExpression(operandExpression, contextualType.isAnyFloat ? Type.i64 : contextualType);
operand = this.compileExpression(operandExpression, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType.isLongInteger
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));

View File

@ -60,6 +60,7 @@ export enum DiagnosticCode {
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
Duplicate_function_implementation = 2393,
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property = 2540,
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
Expected_0_arguments_but_got_1 = 2554,
Expected_at_least_0_arguments_but_got_1 = 2555,
@ -128,6 +129,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2391: return "Function implementation is missing or not immediately following the declaration.";
case 2393: return "Duplicate function implementation.";
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
case 2540: return "Cannot assign to '{0}' because it is a constant or a read-only property.";
case 2541: return "The target of an assignment must be a variable or a property access.";
case 2554: return "Expected {0} arguments, but got {1}.";
case 2555: return "Expected at least {0} arguments, but got {1}.";

View File

@ -60,6 +60,7 @@
"Function implementation is missing or not immediately following the declaration.": 2391,
"Duplicate function implementation.": 2393,
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
"Cannot assign to '{0}' because it is a constant or a read-only property.": 2540,
"The target of an assignment must be a variable or a property access.": 2541,
"Expected {0} arguments, but got {1}.": 2554,
"Expected at least {0} arguments, but got {1}.": 2555,

View File

@ -350,7 +350,7 @@ export class Parser extends DiagnosticEmitter {
const members: VariableDeclaration[] = new Array();
const isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do {
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare);
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers);
if (!member)
return null;
members.push(<VariableDeclaration>member);
@ -361,7 +361,7 @@ export class Parser extends DiagnosticEmitter {
return ret;
}
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false): VariableDeclaration | null {
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false, parentModifiers: Modifier[]): VariableDeclaration | null {
// Identifier (':' Type)? ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range());
@ -383,7 +383,7 @@ export class Parser extends DiagnosticEmitter {
if (!initializer)
return null;
}
return Statement.createVariableDeclaration(identifier, type, initializer, Range.join(identifier.range, tn.range()));
return Statement.createVariableDeclaration(identifier, type, initializer, parentModifiers, Range.join(identifier.range, tn.range()));
}
parseEnum(tn: Tokenizer, modifiers: Modifier[]): EnumDeclaration | null {

View File

@ -764,7 +764,7 @@ export class Global extends Element {
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
get isGlobalExport(): bool { return this.globalExportName != null; }
get isMutable(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
get isMutable(): bool { return this.declaration ? !hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
}
/** A function parameter. */