From 2d0f5f3087cc6e27cca86c53f668fd48fb38e011 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Fri, 5 Jan 2018 01:55:59 +0100 Subject: [PATCH] Comma expressions fwiw --- src/ast.ts | 122 +++++++----- src/builtins.ts | 16 +- src/compiler.ts | 28 ++- src/parser.ts | 172 ++++++++-------- src/types.ts | 83 ++++++-- std/assembly/array.ts | 19 ++ tests/compiler/comma.optimized.wast | 152 ++++++++++++++ tests/compiler/comma.ts | 24 +++ tests/compiler/comma.wast | 294 ++++++++++++++++++++++++++++ tests/compiler/std/array.wast | 3 + tests/compiler/std/heap.wast | 3 + 11 files changed, 764 insertions(+), 152 deletions(-) create mode 100644 tests/compiler/comma.optimized.wast create mode 100644 tests/compiler/comma.ts create mode 100644 tests/compiler/comma.wast diff --git a/src/ast.ts b/src/ast.ts index 968e80b9..cabb9f47 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -39,6 +39,7 @@ export enum NodeKind { ASSERTION, BINARY, CALL, + COMMA, ELEMENTACCESS, FALSE, LITERAL, @@ -118,14 +119,14 @@ export abstract class Node { // expressions - static createIdentifier(name: string, range: Range): IdentifierExpression { + static createIdentifierExpression(name: string, range: Range): IdentifierExpression { var expr = new IdentifierExpression(); expr.range = range; expr.name = name; return expr; } - static createArrayLiteral(elementExpressions: (Expression | null)[], range: Range): ArrayLiteralExpression { + static createArrayLiteralExpression(elementExpressions: (Expression | null)[], range: Range): ArrayLiteralExpression { var expr = new ArrayLiteralExpression(); expr.range = range; for (var i = 0, k = (expr.elementExpressions = elementExpressions).length; i < k; ++i) @@ -134,7 +135,7 @@ export abstract class Node { return expr; } - static createAssertion(assertionKind: AssertionKind, expression: Expression, toType: TypeNode, range: Range): AssertionExpression { + static createAssertionExpression(assertionKind: AssertionKind, expression: Expression, toType: TypeNode, range: Range): AssertionExpression { var expr = new AssertionExpression(); expr.range = range; expr.assertionKind = assertionKind; @@ -143,7 +144,7 @@ export abstract class Node { return expr; } - static createBinary(operator: Token, left: Expression, right: Expression, range: Range): BinaryExpression { + static createBinaryExpression(operator: Token, left: Expression, right: Expression, range: Range): BinaryExpression { var expr = new BinaryExpression(); expr.range = range; expr.operator = operator; @@ -152,7 +153,7 @@ export abstract class Node { return expr; } - static createCall(expression: Expression, typeArguments: TypeNode[] | null, args: Expression[], range: Range): CallExpression { + static createCallExpression(expression: Expression, typeArguments: TypeNode[] | null, args: Expression[], range: Range): CallExpression { var expr = new CallExpression(); expr.range = range; (expr.expression = expression).parent = expr; @@ -164,13 +165,21 @@ export abstract class Node { return expr; } - static createConstructor(range: Range): ConstructorExpression { + static createCommaExpression(expressions: Expression[], range: Range): CommaExpression { + var expr = new CommaExpression(); + expr.range = range; + for (var i = 0, k = (expr.expressions = expressions).length; i < k; ++i) + expressions[i].parent = expr; + return expr; + } + + static createConstructorExpression(range: Range): ConstructorExpression { var expr = new ConstructorExpression(); expr.range = range; return expr; } - static createElementAccess(expression: Expression, element: Expression, range: Range): ElementAccessExpression { + static createElementAccessExpression(expression: Expression, element: Expression, range: Range): ElementAccessExpression { var expr = new ElementAccessExpression(); expr.range = range; (expr.expression = expression).parent = expr; @@ -178,27 +187,27 @@ export abstract class Node { return expr; } - static createFalse(range: Range): FalseExpression { + static createFalseExpression(range: Range): FalseExpression { var expr = new FalseExpression(); expr.range = range; return expr; } - static createFloatLiteral(value: f64, range: Range): FloatLiteralExpression { + static createFloatLiteralExpression(value: f64, range: Range): FloatLiteralExpression { var expr = new FloatLiteralExpression(); expr.range = range; expr.value = value; return expr; } - static createIntegerLiteral(value: I64, range: Range): IntegerLiteralExpression { + static createIntegerLiteralExpression(value: I64, range: Range): IntegerLiteralExpression { var expr = new IntegerLiteralExpression(); expr.range = range; expr.value = value; return expr; } - static createNew(expression: Expression, typeArguments: TypeNode[] | null, args: Expression[], range: Range): NewExpression { + static createNewExpression(expression: Expression, typeArguments: TypeNode[] | null, args: Expression[], range: Range): NewExpression { var expr = new NewExpression(); expr.range = range; (expr.expression = expression).parent = expr; @@ -210,20 +219,20 @@ export abstract class Node { return expr; } - static createNull(range: Range): NullExpression { + static createNullExpression(range: Range): NullExpression { var expr = new NullExpression(); expr.range = range; return expr; } - static createParenthesized(expression: Expression, range: Range): ParenthesizedExpression { + static createParenthesizedExpression(expression: Expression, range: Range): ParenthesizedExpression { var expr = new ParenthesizedExpression(); expr.range = range; (expr.expression = expression).parent = expr; return expr; } - static createPropertyAccess(expression: Expression, property: IdentifierExpression, range: Range): PropertyAccessExpression { + static createPropertyAccessExpression(expression: Expression, property: IdentifierExpression, range: Range): PropertyAccessExpression { var expr = new PropertyAccessExpression(); expr.range = range; (expr.expression = expression).parent = expr; @@ -231,14 +240,14 @@ export abstract class Node { return expr; } - static createRegexpLiteral(value: string, range: Range): RegexpLiteralExpression { + static createRegexpLiteralExpression(value: string, range: Range): RegexpLiteralExpression { var expr = new RegexpLiteralExpression(); expr.range = range; expr.value = value; return expr; } - static createTernary(condition: Expression, ifThen: Expression, ifElse: Expression, range: Range): TernaryExpression { + static createTernaryExpression(condition: Expression, ifThen: Expression, ifElse: Expression, range: Range): TernaryExpression { var expr = new TernaryExpression(); expr.range = range; (expr.condition = condition).parent = expr; @@ -247,32 +256,32 @@ export abstract class Node { return expr; } - static createStringLiteral(value: string, range: Range): StringLiteralExpression { + static createStringLiteralExpression(value: string, range: Range): StringLiteralExpression { var expr = new StringLiteralExpression(); expr.range = range; expr.value = value; return expr; } - static createSuper(range: Range): SuperExpression { + static createSuperExpression(range: Range): SuperExpression { var expr = new SuperExpression(); expr.range = range; return expr; } - static createThis(range: Range): ThisExpression { + static createThisExpression(range: Range): ThisExpression { var expr = new ThisExpression(); expr.range = range; return expr; } - static createTrue(range: Range): TrueExpression { + static createTrueExpression(range: Range): TrueExpression { var expr = new TrueExpression(); expr.range = range; return expr; } - static createUnaryPostfix(operator: Token, expression: Expression, range: Range): UnaryPostfixExpression { + static createUnaryPostfixExpression(operator: Token, expression: Expression, range: Range): UnaryPostfixExpression { var expr = new UnaryPostfixExpression(); expr.range = range; expr.operator = operator; @@ -280,7 +289,7 @@ export abstract class Node { return expr; } - static createUnaryPrefix(operator: Token, expression: Expression, range: Range): UnaryPrefixExpression { + static createUnaryPrefixExpression(operator: Token, expression: Expression, range: Range): UnaryPrefixExpression { var expr = new UnaryPrefixExpression(); expr.range = range; expr.operator = operator; @@ -290,7 +299,7 @@ export abstract class Node { // statements - static createBlock(statements: Statement[], range: Range): BlockStatement { + static createBlockStatement(statements: Statement[], range: Range): BlockStatement { var stmt = new BlockStatement(); stmt.range = range; for (var i: i32 = 0, k: i32 = (stmt.statements = statements).length; i < k; ++i) @@ -298,7 +307,7 @@ export abstract class Node { return stmt; } - static createBreak(label: IdentifierExpression | null, range: Range): BreakStatement { + static createBreakStatement(label: IdentifierExpression | null, range: Range): BreakStatement { var stmt = new BreakStatement(); stmt.range = range; if (stmt.label = label) @@ -306,7 +315,7 @@ export abstract class Node { return stmt; } - static createClass(identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): ClassDeclaration { + static createClassDeclaration(identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): ClassDeclaration { var stmt = new ClassDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -327,7 +336,7 @@ export abstract class Node { return stmt; } - static createContinue(label: IdentifierExpression | null, range: Range): ContinueStatement { + static createContinueStatement(label: IdentifierExpression | null, range: Range): ContinueStatement { var stmt = new ContinueStatement(); stmt.range = range; if (stmt.label = label) @@ -345,7 +354,7 @@ export abstract class Node { return stmt; } - static createDo(statement: Statement, condition: Expression, range: Range): DoStatement { + static createDoStatement(statement: Statement, condition: Expression, range: Range): DoStatement { var stmt = new DoStatement(); stmt.range = range; (stmt.statement = statement).parent = stmt; @@ -353,13 +362,13 @@ export abstract class Node { return stmt; } - static createEmpty(range: Range): EmptyStatement { + static createEmptyStatement(range: Range): EmptyStatement { var stmt = new EmptyStatement(); stmt.range = range; return stmt; } - static createEnum(identifier: IdentifierExpression, members: EnumValueDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): EnumDeclaration { + static createEnumDeclaration(identifier: IdentifierExpression, members: EnumValueDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): EnumDeclaration { var stmt = new EnumDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -374,7 +383,7 @@ export abstract class Node { return stmt; } - static createEnumValue(identifier: IdentifierExpression, value: Expression | null, range: Range): EnumValueDeclaration { + static createEnumValueDeclaration(identifier: IdentifierExpression, value: Expression | null, range: Range): EnumValueDeclaration { var stmt = new EnumValueDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -383,7 +392,7 @@ export abstract class Node { return stmt; } - static createExport(members: ExportMember[], path: StringLiteralExpression | null, modifiers: Modifier[] | null, range: Range): ExportStatement { + static createExportStatement(members: ExportMember[], path: StringLiteralExpression | null, modifiers: Modifier[] | null, range: Range): ExportStatement { var stmt = new ExportStatement(); stmt.range = range; for (var i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt; @@ -396,7 +405,7 @@ export abstract class Node { return stmt; } - static createExportImport(identifier: IdentifierExpression, asIdentifier: IdentifierExpression, range: Range): ExportImportStatement { + static createExportImportStatement(identifier: IdentifierExpression, asIdentifier: IdentifierExpression, range: Range): ExportImportStatement { var stmt = new ExportImportStatement(); stmt.range = range; (stmt.identifier = identifier).parent = stmt; @@ -413,14 +422,14 @@ export abstract class Node { } /** Creates an expression statement. */ - static createExpression(expression: Expression): ExpressionStatement { + static createExpressionStatement(expression: Expression): ExpressionStatement { var stmt = new ExpressionStatement(); stmt.range = expression.range; (stmt.expression = expression).parent = stmt; return stmt; } - static createIf(condition: Expression, ifTrue: Statement, ifFalse: Statement | null, range: Range): IfStatement { + static createIfStatement(condition: Expression, ifTrue: Statement, ifFalse: Statement | null, range: Range): IfStatement { var stmt = new IfStatement(); stmt.range = range; (stmt.condition = condition).parent = stmt; @@ -430,7 +439,7 @@ export abstract class Node { return stmt; } - static createImport(declarations: ImportDeclaration[], path: StringLiteralExpression, range: Range): ImportStatement { + static createImportStatement(declarations: ImportDeclaration[], path: StringLiteralExpression, range: Range): ImportStatement { var stmt = new ImportStatement(); stmt.range = range; for (var i: i32 = 0, k: i32 = (stmt.declarations = declarations).length; i < k; ++i) @@ -442,7 +451,7 @@ export abstract class Node { return stmt; } - static createImportAll(identifier: IdentifierExpression, path: StringLiteralExpression, range: Range): ImportStatement { + static createImportStatementWithWildcard(identifier: IdentifierExpression, path: StringLiteralExpression, range: Range): ImportStatement { var stmt = new ImportStatement(); stmt.range = range; stmt.declarations = null; @@ -461,7 +470,7 @@ export abstract class Node { return elem; } - static createInterface(identifier: IdentifierExpression, extendsType: TypeNode | null, members: DeclarationStatement[], modifiers: Modifier[] | null, range: Range): InterfaceDeclaration { + static createInterfaceDeclaration(identifier: IdentifierExpression, extendsType: TypeNode | null, members: DeclarationStatement[], modifiers: Modifier[] | null, range: Range): InterfaceDeclaration { var stmt = new InterfaceDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -475,7 +484,7 @@ export abstract class Node { return stmt; } - static createField(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FieldDeclaration { + static createFieldDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FieldDeclaration { var stmt = new FieldDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -492,7 +501,7 @@ export abstract class Node { return stmt; } - static createFor(initializer: Statement | null, condition: Expression | null, incrementor: Expression | null, statement: Statement, range: Range): ForStatement { + static createForStatement(initializer: Statement | null, condition: Expression | null, incrementor: Expression | null, statement: Statement, range: Range): ForStatement { var stmt = new ForStatement(); stmt.range = range; if (stmt.initializer = initializer) @@ -526,7 +535,7 @@ export abstract class Node { return elem; } - static createFunction(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FunctionDeclaration { + static createFunctionDeclaration(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FunctionDeclaration { var stmt = new FunctionDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -548,7 +557,7 @@ export abstract class Node { return stmt; } - static createMethod(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): MethodDeclaration { + static createMethodDeclaration(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): MethodDeclaration { var stmt = new MethodDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -577,7 +586,7 @@ export abstract class Node { return elem; } - static createNamespace(identifier: IdentifierExpression, members: Statement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): NamespaceDeclaration { + static createNamespaceDeclaration(identifier: IdentifierExpression, members: Statement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): NamespaceDeclaration { var stmt = new NamespaceDeclaration(); stmt.range = range; (stmt.name = identifier).parent = stmt; @@ -592,7 +601,7 @@ export abstract class Node { return stmt; } - static createReturn(expression: Expression | null, range: Range): ReturnStatement { + static createReturnStatement(expression: Expression | null, range: Range): ReturnStatement { var stmt = new ReturnStatement(); stmt.range = range; if (stmt.value = expression) @@ -600,7 +609,7 @@ export abstract class Node { return stmt; } - static createSwitch(expression: Expression, cases: SwitchCase[], range: Range): SwitchStatement { + static createSwitchStatement(expression: Expression, cases: SwitchCase[], range: Range): SwitchStatement { var stmt = new SwitchStatement(); stmt.range = range; (stmt.condition = expression).parent = stmt; @@ -619,14 +628,14 @@ export abstract class Node { return elem; } - static createThrow(expression: Expression, range: Range): ThrowStatement { + static createThrowStatement(expression: Expression, range: Range): ThrowStatement { var stmt = new ThrowStatement(); stmt.range = range; (stmt.value = expression).parent = stmt; return stmt; } - static createTry(statements: Statement[], catchVariable: IdentifierExpression | null, catchStatements: Statement[] | null, finallyStatements: Statement[] | null, range: Range): TryStatement { + static createTryStatement(statements: Statement[], catchVariable: IdentifierExpression | null, catchStatements: Statement[] | null, finallyStatements: Statement[] | null, range: Range): TryStatement { var stmt = new TryStatement(); stmt.range = range; for (var i = 0, k = (stmt.statements = statements).length; i < k; ++i) @@ -656,7 +665,7 @@ export abstract class Node { return stmt; } - static createVariable(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement { + static createVariableStatement(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement { var stmt = new VariableStatement(); stmt.range = range; for (var i = 0, k = (stmt.declarations = declarations).length; i < k; ++i) @@ -683,7 +692,7 @@ export abstract class Node { return elem; } - static createWhile(condition: Expression, statement: Statement, range: Range): WhileStatement { + static createWhileStatement(condition: Expression, statement: Statement, range: Range): WhileStatement { var stmt = new WhileStatement(); stmt.range = range; (stmt.condition = condition).parent = stmt; @@ -886,6 +895,23 @@ export class CallExpression extends Expression { } } +/** Represents a comma expression composed of multiple sequential expressions. */ +export class CommaExpression extends Expression { + + kind = NodeKind.COMMA; + + /** Sequential expressions. */ + expressions: Expression[]; + + serialize(sb: string[]): void { + this.expressions[0].serialize(sb); + for (var i = 1, k = this.expressions.length; i < k; ++i) { + sb.push(","); + this.expressions[i].serialize(sb); + } + } +} + /** Represents a `constructor` expression. */ export class ConstructorExpression extends IdentifierExpression { kind = NodeKind.CONSTRUCTOR; diff --git a/src/builtins.ts b/src/builtins.ts index 0a5bb7b8..ba814777 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -15,7 +15,7 @@ import { } from "./ast"; import { - Type + Type, TypeKind } from "./types"; import { @@ -169,8 +169,8 @@ function addFunction(program: Program, name: string, isGeneric: bool = false): F } /** Compiles a get of a built-in global. */ -export function compileGetConstant(compiler: Compiler, global: Global): ExpressionRef { - switch (global.internalName) { +export function compileGetConstant(compiler: Compiler, global: Global, reportNode: Node): ExpressionRef { + switch (global.internalName) { // switching on strings should become a compiler optimization eventually case "NaN": if (compiler.currentType == Type.f32) @@ -186,10 +186,9 @@ export function compileGetConstant(compiler: Compiler, global: Global): Expressi case "HEAP_BASE": // constant, but never inlined return compiler.module.createGetGlobal("HEAP_BASE", (compiler.currentType = global.type).toNativeType()); - - default: - throw new Error("not implemented: " + global.internalName); } + compiler.error(DiagnosticCode.Operation_not_supported, reportNode.range); + return compiler.module.createUnreachable(); } /** Compiles a call to a built-in function. */ @@ -283,7 +282,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode)) return module.createUnreachable(); if ((compiler.currentType = (typeArguments)[0]).isAnyInteger) { - arg0 = compiler.compileExpression(operands[0], (typeArguments)[0]); + arg0 = compiler.compileExpression(operands[0], (typeArguments)[0]); return (compiler.currentType = (typeArguments)[0]).isLongInteger // sic ? module.createUnary(UnaryOp.ClzI64, arg0) : (typeArguments)[0].isSmallInteger @@ -797,7 +796,8 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty return module.createUnreachable(); return compiler.compileExpression(operands[0], Type.f64, ConversionKind.EXPLICIT); } - return 0; + compiler.error(DiagnosticCode.Operation_not_supported, reportNode.range); + return module.createUnreachable(); } /** Pre-validates a call to a built-in function. */ diff --git a/src/compiler.ts b/src/compiler.ts index cb735a66..ec04ec0e 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -89,6 +89,7 @@ import { AssertionExpression, BinaryExpression, CallExpression, + CommaExpression, ElementAccessExpression, FloatLiteralExpression, IdentifierExpression, @@ -338,7 +339,7 @@ export class Compiler extends DiagnosticEmitter { } compileGlobal(global: Global): bool { - if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetConstant(this, global))) + if (global.isCompiled || global.isBuiltIn) return true; var declaration = global.declaration; @@ -1103,6 +1104,10 @@ export class Compiler extends DiagnosticEmitter { expr = this.compileCallExpression(expression, contextualType); break; + case NodeKind.COMMA: + expr = this.compileCommaExpression(expression, contextualType); + break; + case NodeKind.ELEMENTACCESS: expr = this.compileElementAccessExpression(expression, contextualType); break; @@ -2123,8 +2128,13 @@ export class Compiler extends DiagnosticEmitter { var elementType: Type; switch (element.kind) { - case ElementKind.LOCAL: case ElementKind.GLOBAL: + if (!this.compileGlobal(element)) // reports; not yet compiled if a static field compiled as a global + return this.module.createUnreachable(); + assert((element).type != Type.void); + // fall-through + + case ElementKind.LOCAL: case ElementKind.FIELD: elementType = (element).type; break; @@ -2356,6 +2366,16 @@ export class Compiler extends DiagnosticEmitter { return this.module.createCall(functionInstance.internalName, operands, functionInstance.returnType.toNativeType()); } + compileCommaExpression(expression: CommaExpression, contextualType: Type): ExpressionRef { + var expressions = expression.expressions; + var k = expressions.length; + var exprs = new Array(k--); + for (var i = 0; i < k; ++i) + exprs[i] = this.compileExpression(expressions[i], Type.void); // drop all + exprs[i] = this.compileExpression(expressions[i], contextualType); // except last + return this.module.createBlock(null, exprs, this.currentType.toNativeType()); + } + compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef { var resolved = this.program.resolveElementAccess(expression, this.currentFunction); // reports if (!resolved) @@ -2426,7 +2446,7 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.GLOBAL: if (element.isBuiltIn) - return compileBuiltinGetConstant(this, element); + return compileBuiltinGetConstant(this, element, expression); if (!this.compileGlobal(element)) // reports; not yet compiled if a static field compiled as a global return this.module.createUnreachable(); assert((element).type != Type.void); @@ -2500,6 +2520,8 @@ export class Compiler extends DiagnosticEmitter { switch (element.kind) { case ElementKind.GLOBAL: // static property + if (element.isBuiltIn) + return compileBuiltinGetConstant(this, element, propertyAccess); if (!this.compileGlobal(element)) // reports; not yet compiled if a static field compiled as a global return this.module.createUnreachable(); assert((element).type != Type.void); diff --git a/src/parser.ts b/src/parser.ts index e602257e..30085b03 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -258,7 +258,7 @@ export class Parser extends DiagnosticEmitter { // void if (token == Token.VOID) - return Node.createType(Node.createIdentifier("void", tn.range()), [], false, tn.range(startPos, tn.pos)); + return Node.createType(Node.createIdentifierExpression("void", tn.range()), [], false, tn.range(startPos, tn.pos)); var type: TypeNode; @@ -278,20 +278,20 @@ export class Parser extends DiagnosticEmitter { // this } else if (token == Token.THIS) { - type = Node.createType(Node.createThis(tn.range()), [], false, tn.range(startPos, tn.pos)); + type = Node.createType(Node.createThisExpression(tn.range()), [], false, tn.range(startPos, tn.pos)); // true } else if (token == Token.TRUE || token == Token.FALSE) { - type = Node.createType(Node.createIdentifier("bool", tn.range()), [], false, tn.range(startPos, tn.pos)); + type = Node.createType(Node.createIdentifierExpression("bool", tn.range()), [], false, tn.range(startPos, tn.pos)); // string literal } else if (token == Token.STRINGLITERAL) { tn.readString(); - type = Node.createType(Node.createIdentifier("string", tn.range()), [], false, tn.range(startPos, tn.pos)); + type = Node.createType(Node.createIdentifierExpression("string", tn.range()), [], false, tn.range(startPos, tn.pos)); // Name } else if (token == Token.IDENTIFIER) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var parameters = new Array(); var nullable = false; @@ -347,7 +347,7 @@ export class Parser extends DiagnosticEmitter { return null; } } - type = Node.createType(Node.createIdentifier("Array", bracketRange), [ type ], nullable, tn.range(startPos, tn.pos)); + type = Node.createType(Node.createIdentifierExpression("Array", bracketRange), [ type ], nullable, tn.range(startPos, tn.pos)); if (nullable) break; } @@ -362,11 +362,11 @@ export class Parser extends DiagnosticEmitter { var startPos = tn.tokenPos; if (tn.skip(Token.IDENTIFIER)) { var name = tn.readIdentifier(); - var expression: Expression = Node.createIdentifier(name, tn.range(startPos, tn.pos)); + var expression: Expression = Node.createIdentifierExpression(name, tn.range(startPos, tn.pos)); while (tn.skip(Token.DOT)) { if (tn.skip(Token.IDENTIFIER)) { name = tn.readIdentifier(); - expression = Node.createPropertyAccess(expression, Node.createIdentifier(name, tn.range()), tn.range(startPos, tn.pos)); + expression = Node.createPropertyAccessExpression(expression, Node.createIdentifierExpression(name, tn.range()), tn.range(startPos, tn.pos)); } else { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; @@ -396,7 +396,7 @@ export class Parser extends DiagnosticEmitter { members.push(member); } while (tn.skip(Token.COMMA)); - var ret = Node.createVariable(members, modifiers, decorators, tn.range(startPos, tn.pos)); + var ret = Node.createVariableStatement(members, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -407,7 +407,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; } - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var type: TypeNode | null = null; if (tn.skip(Token.COLON)) @@ -437,7 +437,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; } - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); if (tn.next() != Token.OPENBRACE) { this.error(DiagnosticCode._0_expected, tn.range(), "{"); return null; @@ -455,7 +455,7 @@ export class Parser extends DiagnosticEmitter { return null; } } - var ret = Node.createEnum(identifier, members, modifiers, decorators, tn.range(startPos, tn.pos)); + var ret = Node.createEnumDeclaration(identifier, members, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -466,14 +466,14 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; } - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var value: Expression | null = null; if (tn.skip(Token.EQUALS)) { value = this.parseExpression(tn, Precedence.COMMA + 1); if (!value) return null; } - return Node.createEnumValue(identifier, value, Range.join(identifier.range, tn.range())); + return Node.createEnumValueDeclaration(identifier, value, Range.join(identifier.range, tn.range())); } parseReturn(tn: Tokenizer): ReturnStatement | null { @@ -484,7 +484,7 @@ export class Parser extends DiagnosticEmitter { if (!expr) return null; } - var ret = Node.createReturn(expr, tn.range()); + var ret = Node.createReturnStatement(expr, tn.range()); tn.skip(Token.SEMICOLON); return ret; } @@ -511,7 +511,7 @@ export class Parser extends DiagnosticEmitter { parseTypeParameter(tn: Tokenizer): TypeParameter | null { // Identifier ('extends' Type)? if (tn.next() == Token.IDENTIFIER) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var extendsType: TypeNode | null = null; if (tn.skip(Token.EXTENDS)) { extendsType = this.parseType(tn); @@ -553,7 +553,7 @@ export class Parser extends DiagnosticEmitter { if (tn.skip(Token.IDENTIFIER)) { if (!isRest) startRange = tn.range(); - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var type: TypeNode | null = null; if (tn.skip(Token.COLON)) { type = this.parseType(tn); @@ -580,7 +580,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos)); return null; } - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var typeParameters: TypeParameter[] | null = null; if (tn.skip(Token.LESSTHAN)) { typeParameters = this.parseTypeParameters(tn); @@ -627,7 +627,7 @@ export class Parser extends DiagnosticEmitter { } } else if (!isDeclare) this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range(tn.pos)); - var ret = Node.createFunction(identifier, typeParameters, parameters, returnType, statements, modifiers, decorators, tn.range(startPos, tn.pos)); + var ret = Node.createFunctionDeclaration(identifier, typeParameters, parameters, returnType, statements, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -641,7 +641,7 @@ export class Parser extends DiagnosticEmitter { : tn.tokenPos; if (tn.skip(Token.IDENTIFIER)) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var typeParameters: TypeParameter[] | null; if (tn.skip(Token.LESSTHAN)) { @@ -679,7 +679,7 @@ export class Parser extends DiagnosticEmitter { members.push(member); } while (!tn.skip(Token.CLOSEBRACE)); } - return Node.createClass(identifier, typeParameters, extendsType, implementsTypes, members, modifiers, decorators, tn.range(startPos, tn.pos)); + return Node.createClassDeclaration(identifier, typeParameters, extendsType, implementsTypes, members, modifiers, decorators, tn.range(startPos, tn.pos)); } else this.error(DiagnosticCode._0_expected, tn.range(), "{"); } else @@ -739,8 +739,8 @@ export class Parser extends DiagnosticEmitter { if (tn.skip(Token.CONSTRUCTOR) || tn.skip(Token.IDENTIFIER)) { // order is important var identifier: IdentifierExpression = tn.token == Token.CONSTRUCTOR - ? Node.createConstructor(tn.range()) - : Node.createIdentifier(tn.readIdentifier(), tn.range()); + ? Node.createConstructorExpression(tn.range()) + : Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var typeParameters: TypeParameter[] | null; if (tn.skip(Token.LESSTHAN)) { if (identifier.kind == NodeKind.CONSTRUCTOR) @@ -794,7 +794,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range()); // recoverable } - var retMethod = Node.createMethod(identifier, typeParameters, parameters, returnType, statements, modifiers, decorators, tn.range(startPos, tn.pos)); + var retMethod = Node.createMethodDeclaration(identifier, typeParameters, parameters, returnType, statements, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return retMethod; @@ -820,7 +820,7 @@ export class Parser extends DiagnosticEmitter { if (!initializer) return null; } - var retField = Node.createField(identifier, type, initializer, modifiers, decorators, tn.range(startPos, tn.pos)); + var retField = Node.createFieldDeclaration(identifier, type, initializer, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return retField; } @@ -833,7 +833,7 @@ export class Parser extends DiagnosticEmitter { // at 'namespace': Identifier '{' (Variable | Function)* '}' var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos; if (tn.skip(Token.IDENTIFIER)) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); if (tn.skip(Token.OPENBRACE)) { var members = new Array(); while (!tn.skip(Token.CLOSEBRACE)) { @@ -842,7 +842,7 @@ export class Parser extends DiagnosticEmitter { return null; members.push(member); } - var ret = Node.createNamespace(identifier, members, modifiers, decorators, tn.range(startPos, tn.pos)); + var ret = Node.createNamespaceDeclaration(identifier, members, modifiers, decorators, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else @@ -872,13 +872,13 @@ export class Parser extends DiagnosticEmitter { var path: StringLiteralExpression | null = null; if (tn.skip(Token.FROM)) { if (tn.skip(Token.STRINGLITERAL)) - path = Node.createStringLiteral(tn.readString(), tn.range()); + path = Node.createStringLiteralExpression(tn.readString(), tn.range()); else { this.error(DiagnosticCode.String_literal_expected, tn.range()); return null; } } - var ret = Node.createExport(members, path, modifiers, tn.range(startPos, tn.pos)); + var ret = Node.createExportStatement(members, path, modifiers, tn.range(startPos, tn.pos)); if (ret.normalizedPath && !this.seenlog.has(ret.normalizedPath)) { this.backlog.push(ret.normalizedPath); this.seenlog.add(ret.normalizedPath); @@ -893,11 +893,11 @@ export class Parser extends DiagnosticEmitter { parseExportMember(tn: Tokenizer): ExportMember | null { // Identifier ('as' Identifier)? if (tn.skip(Token.IDENTIFIER)) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var asIdentifier: IdentifierExpression | null = null; if (tn.skip(Token.AS)) { if (tn.skip(Token.IDENTIFIER)) - asIdentifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); else { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; @@ -931,7 +931,7 @@ export class Parser extends DiagnosticEmitter { } else if (tn.skip(Token.ASTERISK)) { if (tn.skip(Token.AS)) { if (tn.skip(Token.IDENTIFIER)) { - namespaceName = Node.createIdentifier(tn.readIdentifier(), tn.range()); + namespaceName = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); } else { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; @@ -946,17 +946,17 @@ export class Parser extends DiagnosticEmitter { } if (tn.skip(Token.FROM)) { if (tn.skip(Token.STRINGLITERAL)) { - var path = Node.createStringLiteral(tn.readString(), tn.range()); + var path = Node.createStringLiteralExpression(tn.readString(), tn.range()); var ret: ImportStatement; if (members) { if (!namespaceName) - ret = Node.createImport(members, path, tn.range(startPos, tn.pos)); + ret = Node.createImportStatement(members, path, tn.range(startPos, tn.pos)); else { assert(false); return null; } } else if (namespaceName) { - ret = Node.createImportAll(namespaceName, path, tn.range(startPos, tn.pos)); + ret = Node.createImportStatementWithWildcard(namespaceName, path, tn.range(startPos, tn.pos)); } else { assert(false); return null; @@ -977,11 +977,11 @@ export class Parser extends DiagnosticEmitter { parseImportDeclaration(tn: Tokenizer): ImportDeclaration | null { // Identifier ('as' Identifier)? if (tn.skip(Token.IDENTIFIER)) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var asIdentifier: IdentifierExpression | null = null; if (tn.skip(Token.AS)) { if (tn.skip(Token.IDENTIFIER)) - asIdentifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); else { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; @@ -996,11 +996,11 @@ export class Parser extends DiagnosticEmitter { parseExportImport(tn: Tokenizer, startRange: Range): ExportImportStatement | null { // at 'export' 'import': Identifier ('=' Identifier)? ';'? if (tn.skip(Token.IDENTIFIER)) { - var asIdentifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var asIdentifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); if (tn.skip(Token.EQUALS)) { if (tn.skip(Token.IDENTIFIER)) { - var identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); - var ret = Node.createExportImport(identifier, asIdentifier, Range.join(startRange, tn.range())); + var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); + var ret = Node.createExportImportStatement(identifier, asIdentifier, Range.join(startRange, tn.range())); tn.skip(Token.SEMICOLON); return ret; } else @@ -1049,7 +1049,7 @@ export class Parser extends DiagnosticEmitter { return this.parseReturn(tn); case Token.SEMICOLON: - return Node.createEmpty(tn.range(tn.tokenPos)); + return Node.createEmptyStatement(tn.range(tn.tokenPos)); case Token.SWITCH: return this.parseSwitchStatement(tn); @@ -1082,7 +1082,7 @@ export class Parser extends DiagnosticEmitter { return null; statements.push(statement); } - var ret = Node.createBlock(statements, tn.range(startPos, tn.pos)); + var ret = Node.createBlockStatement(statements, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -1092,9 +1092,9 @@ export class Parser extends DiagnosticEmitter { var identifier: IdentifierExpression | null = null; if (tn.peek(true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) { tn.next(true); - identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); } - var ret = Node.createBreak(identifier, tn.range()); + var ret = Node.createBreakStatement(identifier, tn.range()); tn.skip(Token.SEMICOLON); return ret; } @@ -1104,9 +1104,9 @@ export class Parser extends DiagnosticEmitter { var identifier: IdentifierExpression | null = null; if (tn.peek(true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) { tn.next(true); - identifier = Node.createIdentifier(tn.readIdentifier(), tn.range()); + identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); } - var ret = Node.createContinue(identifier, tn.range()); + var ret = Node.createContinueStatement(identifier, tn.range()); tn.skip(Token.SEMICOLON); return ret; } @@ -1123,7 +1123,7 @@ export class Parser extends DiagnosticEmitter { if (!condition) return null; if (tn.skip(Token.CLOSEPAREN)) { - var ret = Node.createDo(statement, condition, tn.range(startPos, tn.pos)); + var ret = Node.createDoStatement(statement, condition, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -1140,7 +1140,7 @@ export class Parser extends DiagnosticEmitter { var expr = this.parseExpression(tn); if (!expr) return null; - var ret = Node.createExpression(expr); + var ret = Node.createExpressionStatement(expr); tn.skip(Token.SEMICOLON); return ret; } @@ -1178,7 +1178,7 @@ export class Parser extends DiagnosticEmitter { var statement = this.parseStatement(tn); if (!statement) return null; - return Node.createFor(initializer, condition ? condition.expression : null, incrementor, statement, tn.range(startPos, tn.pos)); + return Node.createForStatement(initializer, condition ? condition.expression : null, incrementor, statement, tn.range(startPos, tn.pos)); } else this.error(DiagnosticCode._0_expected, tn.range(), ";"); } else @@ -1205,7 +1205,7 @@ export class Parser extends DiagnosticEmitter { if (!elseStatement) return null; } - return Node.createIf(condition, statement, elseStatement, tn.range(startPos, tn.pos)); + return Node.createIfStatement(condition, statement, elseStatement, tn.range(startPos, tn.pos)); } this.error(DiagnosticCode._0_expected, tn.range(), ")"); } else @@ -1229,7 +1229,7 @@ export class Parser extends DiagnosticEmitter { return null; cases.push(case_); } - var ret = Node.createSwitch(condition, cases, tn.range(startPos, tn.pos)); + var ret = Node.createSwitchStatement(condition, cases, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else @@ -1289,7 +1289,7 @@ export class Parser extends DiagnosticEmitter { var expression = this.parseExpression(tn); if (!expression) return null; - var ret = Node.createThrow(expression, tn.range(startPos, tn.pos)); + var ret = Node.createThrowStatement(expression, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } @@ -1318,7 +1318,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode.Identifier_expected, tn.range()); return null; } - catchVariable = Node.createIdentifier(tn.readIdentifier(), tn.range()); + catchVariable = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); if (!tn.skip(Token.CLOSEPAREN)) { this.error(DiagnosticCode._0_expected, tn.range(), ")"); return null; @@ -1352,7 +1352,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode._0_expected, tn.range(), "catch"); return null; } - var ret = Node.createTry(statements, catchVariable, catchStatements, finallyStatements, tn.range(startPos, tn.pos)); + var ret = Node.createTryStatement(statements, catchVariable, catchStatements, finallyStatements, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else @@ -1366,7 +1366,7 @@ export class Parser extends DiagnosticEmitter { : modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos; if (tn.skip(Token.IDENTIFIER)) { - var name = Node.createIdentifier(tn.readIdentifier(), tn.range()); + var name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); if (tn.skip(Token.EQUALS)) { var type = this.parseType(tn); if (!type) @@ -1392,7 +1392,7 @@ export class Parser extends DiagnosticEmitter { var statement = this.parseStatement(tn); if (!statement) return null; - var ret = Node.createWhile(expression, statement, tn.range(startPos, tn.pos)); + var ret = Node.createWhileStatement(expression, statement, tn.range(startPos, tn.pos)); tn.skip(Token.SEMICOLON); return ret; } else @@ -1411,11 +1411,11 @@ export class Parser extends DiagnosticEmitter { var expr: Expression | null = null; if (token == Token.NULL) - return Node.createNull(tn.range()); + return Node.createNullExpression(tn.range()); if (token == Token.TRUE) - return Node.createTrue(tn.range()); + return Node.createTrueExpression(tn.range()); if (token == Token.FALSE) - return Node.createFalse(tn.range()); + return Node.createFalseExpression(tn.range()); var p = determinePrecedenceStart(token); if (p != Precedence.INVALID) { @@ -1429,7 +1429,7 @@ export class Parser extends DiagnosticEmitter { if (!operand) return null; if (operand.kind == NodeKind.CALL) - return Node.createNew((operand).expression, (operand).typeArguments, (operand).arguments, tn.range(startPos, tn.pos)); + return Node.createNewExpression((operand).expression, (operand).typeArguments, (operand).arguments, tn.range(startPos, tn.pos)); this.error(DiagnosticCode.Operation_not_supported, tn.range()); return null; } else @@ -1439,7 +1439,7 @@ export class Parser extends DiagnosticEmitter { if (token == Token.PLUS_PLUS || token == Token.MINUS_MINUS) if ((operand).kind != NodeKind.IDENTIFIER && (operand).kind != NodeKind.ELEMENTACCESS && (operand).kind != NodeKind.PROPERTYACCESS) this.error(DiagnosticCode.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, (operand).range); - return Node.createUnaryPrefix(token, operand, tn.range(startPos, tn.pos)); + return Node.createUnaryPrefixExpression(token, operand, tn.range(startPos, tn.pos)); } switch (token) { @@ -1453,7 +1453,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode._0_expected, tn.range(), ")"); return null; } - return Node.createParenthesized(expr, tn.range(startPos, tn.pos)); + return Node.createParenthesizedExpression(expr, tn.range(startPos, tn.pos)); } // ArrayLiteralExpression @@ -1475,7 +1475,7 @@ export class Parser extends DiagnosticEmitter { return null; } } - return Node.createArrayLiteral(elementExpressions, tn.range(startPos, tn.pos)); + return Node.createArrayLiteralExpression(elementExpressions, tn.range(startPos, tn.pos)); } // AssertionExpression (unary prefix) @@ -1490,33 +1490,33 @@ export class Parser extends DiagnosticEmitter { expr = this.parseExpression(tn, Precedence.CALL); if (!expr) return null; - return Node.createAssertion(AssertionKind.PREFIX, expr, toType, tn.range(startPos, tn.pos)); + return Node.createAssertionExpression(AssertionKind.PREFIX, expr, toType, tn.range(startPos, tn.pos)); } // IdentifierExpression case Token.IDENTIFIER: - return Node.createIdentifier(tn.readIdentifier(), tn.range(startPos, tn.pos)); + return Node.createIdentifierExpression(tn.readIdentifier(), tn.range(startPos, tn.pos)); case Token.THIS: - return Node.createThis(tn.range(startPos, tn.pos)); + return Node.createThisExpression(tn.range(startPos, tn.pos)); case Token.CONSTRUCTOR: - return Node.createConstructor(tn.range(startPos, tn.pos)); + return Node.createConstructorExpression(tn.range(startPos, tn.pos)); case Token.SUPER: - return Node.createSuper(tn.range(startPos, tn.pos)); + return Node.createSuperExpression(tn.range(startPos, tn.pos)); // StringLiteralExpression case Token.STRINGLITERAL: - return Node.createStringLiteral(tn.readString(), tn.range(startPos, tn.pos)); + return Node.createStringLiteralExpression(tn.readString(), tn.range(startPos, tn.pos)); // IntegerLiteralExpression case Token.INTEGERLITERAL: - return Node.createIntegerLiteral(tn.readInteger(), tn.range(startPos, tn.pos)); + return Node.createIntegerLiteralExpression(tn.readInteger(), tn.range(startPos, tn.pos)); // FloatLiteralExpression case Token.FLOATLITERAL: - return Node.createFloatLiteral(tn.readFloat(), tn.range(startPos, tn.pos)); + return Node.createFloatLiteralExpression(tn.readFloat(), tn.range(startPos, tn.pos)); // RegexpLiteralExpression /* @@ -1530,7 +1530,7 @@ export class Parser extends DiagnosticEmitter { return regexpLit; */ case Token.REGEXPLITERAL: // not yet supported - return Node.createRegexpLiteral(tn.readRegexp(), tn.range(startPos, tn.pos)); + return Node.createRegexpLiteralExpression(tn.readRegexp(), tn.range(startPos, tn.pos)); default: this.error(DiagnosticCode.Expression_expected, tn.range()); @@ -1593,7 +1593,7 @@ export class Parser extends DiagnosticEmitter { var args = this.parseArguments(tn); if (!args) return null; - expr = Node.createCall(expr, typeArguments, args, tn.range(startPos, tn.pos)); + expr = Node.createCallExpression(expr, typeArguments, args, tn.range(startPos, tn.pos)); } var token: Token; @@ -1608,7 +1608,7 @@ export class Parser extends DiagnosticEmitter { var toType = this.parseType(tn); if (!toType) return null; - expr = Node.createAssertion(AssertionKind.AS, expr, toType, tn.range(startPos, tn.pos)); + expr = Node.createAssertionExpression(AssertionKind.AS, expr, toType, tn.range(startPos, tn.pos)); // ElementAccessExpression } else if (token == Token.OPENBRACKET) { @@ -1617,7 +1617,7 @@ export class Parser extends DiagnosticEmitter { return null; if (tn.skip(Token.CLOSEBRACKET)) - expr = Node.createElementAccess(expr, next, tn.range(startPos, tn.pos)); + expr = Node.createElementAccessExpression(expr, next, tn.range(startPos, tn.pos)); else { this.error(DiagnosticCode._0_expected, tn.range(), "]"); return null; @@ -1627,7 +1627,7 @@ export class Parser extends DiagnosticEmitter { } else if (token == Token.PLUS_PLUS || token == Token.MINUS_MINUS) { if (expr.kind != NodeKind.IDENTIFIER && expr.kind != NodeKind.ELEMENTACCESS && expr.kind != NodeKind.PROPERTYACCESS) this.error(DiagnosticCode.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, expr.range); - expr = Node.createUnaryPostfix(token, expr, tn.range(startPos, tn.pos)); + expr = Node.createUnaryPostfixExpression(token, expr, tn.range(startPos, tn.pos)); // TernaryExpression } else if (token == Token.QUESTION) { @@ -1638,12 +1638,24 @@ export class Parser extends DiagnosticEmitter { var ifElse = this.parseExpression(tn); if (!ifElse) return null; - expr = Node.createTernary(expr, ifThen, ifElse, tn.range(startPos, tn.pos)); + expr = Node.createTernaryExpression(expr, ifThen, ifElse, tn.range(startPos, tn.pos)); } else { this.error(DiagnosticCode._0_expected, tn.range(), ":"); return null; } + // CommaExpression + } else if (token == Token.COMMA) { + var commaExprs = new Array(1); + commaExprs[0] = expr; + do { + expr = this.parseExpression(tn, Precedence.COMMA + 1); + if (!expr) + return null; + commaExprs.push(expr); + } while (tn.skip(Token.COMMA)); + expr = Node.createCommaExpression(commaExprs, tn.range(startPos, tn.pos)); + } else { next = this.parseExpression(tn, isRightAssociative(token) ? nextPrecedence : 1 + nextPrecedence); if (!next) @@ -1652,11 +1664,11 @@ export class Parser extends DiagnosticEmitter { // PropertyAccessExpression if (token == Token.DOT) { if (next.kind == NodeKind.IDENTIFIER) { - expr = Node.createPropertyAccess(expr, next, tn.range(startPos, tn.pos)); + expr = Node.createPropertyAccessExpression(expr, next, tn.range(startPos, tn.pos)); } else if (next.kind == NodeKind.CALL) { // amend var propertyCall = next; if (propertyCall.expression.kind == NodeKind.IDENTIFIER) { - propertyCall.expression = Node.createPropertyAccess(expr, propertyCall.expression, tn.range(startPos, tn.pos)); + propertyCall.expression = Node.createPropertyAccessExpression(expr, propertyCall.expression, tn.range(startPos, tn.pos)); } else throw new Error("unexpected expression kind"); expr = propertyCall; @@ -1667,7 +1679,7 @@ export class Parser extends DiagnosticEmitter { // BinaryExpression } else - expr = Node.createBinary(token, expr, next, tn.range(startPos, tn.pos)); + expr = Node.createBinaryExpression(token, expr, next, tn.range(startPos, tn.pos)); } } return expr; diff --git a/src/types.ts b/src/types.ts index ca8fd5f0..93fce621 100644 --- a/src/types.ts +++ b/src/types.ts @@ -146,27 +146,84 @@ export class Type { /** Converts this type to its respective native type. */ toNativeType(): NativeType { - return this.kind == TypeKind.F32 ? NativeType.F32 - : this.kind == TypeKind.F64 ? NativeType.F64 - : this.isLongInteger ? NativeType.I64 - : this.isAnyInteger ? NativeType.I32 - : NativeType.None; + switch (this.kind) { + + default: + return NativeType.I32; + + case TypeKind.I64: + case TypeKind.U64: + return NativeType.I64; + + case TypeKind.ISIZE: + case TypeKind.USIZE: + return select(NativeType.I64, NativeType.I32, this.size == 64); + + case TypeKind.F32: + return NativeType.F32; + + case TypeKind.F64: + return NativeType.F64; + + case TypeKind.VOID: + return NativeType.None; + } } /** Converts this type to its native `0` value. */ toNativeZero(module: Module): ExpressionRef { - return this.kind == TypeKind.F32 ? module.createF32(0) - : this.kind == TypeKind.F64 ? module.createF64(0) - : this.isLongInteger ? module.createI64(0, 0) - : module.createI32(0); + switch (this.kind) { + + case TypeKind.VOID: + assert(false); + + default: + return module.createI32(0); + + case TypeKind.ISIZE: + case TypeKind.USIZE: + if (this.size != 64) + return module.createI32(0); + // fall-through + + case TypeKind.I64: + case TypeKind.U64: + return module.createI64(0, 0); + + case TypeKind.F32: + return module.createF32(0); + + case TypeKind.F64: + return module.createF64(0); + } } /** Converts this type to its native `1` value. */ toNativeOne(module: Module): ExpressionRef { - return this.kind == TypeKind.F32 ? module.createF32(1) - : this.kind == TypeKind.F64 ? module.createF64(1) - : this.isLongInteger ? module.createI64(1, 0) - : module.createI32(1); + switch (this.kind) { + + case TypeKind.VOID: + assert(false); + + default: + return module.createI32(1); + + case TypeKind.ISIZE: + case TypeKind.USIZE: + if (this.size != 64) + return module.createI32(1); + // fall-through + + case TypeKind.I64: + case TypeKind.U64: + return module.createI64(1, 0); + + case TypeKind.F32: + return module.createF32(1); + + case TypeKind.F64: + return module.createF64(1); + } } /** Converts this type to its signature string. */ diff --git a/std/assembly/array.ts b/std/assembly/array.ts index 6cb321c7..365d59b2 100644 --- a/std/assembly/array.ts +++ b/std/assembly/array.ts @@ -38,3 +38,22 @@ export class Array { // TODO } + +@global +@struct +export class CArray { + + private constructor() {} + + @operator("[]") + get(index: i32): T { + assert(index >= 0); + return load(index * sizeof()); + } + + @operator("[]=") + set(index: i32, value: T): void { + assert(index >= 0); + store(index * sizeof(), value); + } +} diff --git a/tests/compiler/comma.optimized.wast b/tests/compiler/comma.optimized.wast new file mode 100644 index 00000000..337df4f5 --- /dev/null +++ b/tests/compiler/comma.optimized.wast @@ -0,0 +1,152 @@ +(module + (type $v (func)) + (global $comma/a (mut i32) (i32.const 0)) + (global $comma/b (mut i32) (i32.const 0)) + (memory $0 1) + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (local $0 i32) + (set_global $comma/b + (block (result i32) + (set_global $comma/a + (i32.add + (tee_local $0 + (get_global $comma/a) + ) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (if + (i32.ne + (get_global $comma/a) + (i32.const 1) + ) + (unreachable) + ) + (if + (get_global $comma/b) + (unreachable) + ) + (set_global $comma/a + (i32.add + (get_global $comma/a) + (i32.const 1) + ) + ) + (set_global $comma/b + (get_global $comma/a) + ) + (if + (i32.ne + (get_global $comma/a) + (i32.const 2) + ) + (unreachable) + ) + (if + (i32.ne + (get_global $comma/b) + (i32.const 2) + ) + (unreachable) + ) + (set_global $comma/a + (block (result i32) + (set_global $comma/b + (i32.const 0) + ) + (get_global $comma/b) + ) + ) + (set_global $comma/b + (block (result i32) + (set_global $comma/a + (i32.add + (get_global $comma/a) + (i32.const 1) + ) + ) + (get_global $comma/a) + ) + ) + (if + (i32.ne + (get_global $comma/a) + (i32.const 1) + ) + (unreachable) + ) + (if + (i32.ne + (get_global $comma/b) + (i32.const 1) + ) + (unreachable) + ) + (set_global $comma/a + (block (result i32) + (set_global $comma/a + (i32.add + (get_global $comma/a) + (i32.const 1) + ) + ) + (set_global $comma/b + (get_global $comma/a) + ) + (get_global $comma/b) + ) + ) + (if + (i32.ne + (get_global $comma/a) + (i32.const 2) + ) + (unreachable) + ) + (if + (i32.ne + (get_global $comma/b) + (i32.const 2) + ) + (unreachable) + ) + (set_local $0 + (i32.const 0) + ) + (loop $continue|0 + (if + (i32.lt_u + (get_local $0) + (get_global $comma/a) + ) + (block + (set_global $comma/a + (i32.sub + (get_global $comma/a) + (i32.const 1) + ) + ) + (set_local $0 + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (br $continue|0) + ) + ) + ) + (if + (i32.ne + (get_local $0) + (i32.const 1) + ) + (unreachable) + ) + ) +) diff --git a/tests/compiler/comma.ts b/tests/compiler/comma.ts new file mode 100644 index 00000000..a167e124 --- /dev/null +++ b/tests/compiler/comma.ts @@ -0,0 +1,24 @@ +var a = 0, b = 0; + +b = a++, a; // lower precedence (like separate expressions) +assert(a == 1); +assert(b == 0); + +a++, b = a; +assert(a == 2); +assert(b == 2); + +a = b = 0; + +b = (a++, a); // higher precedence +assert(a == 1); +assert(b == 1); + +a = (a++, b = a); +assert(a == 2); +assert(b == 2); + +for (var c = 0; c < a; a--, c++); +assert(c == 1); + +1, 2, 3; // tsc doesn't allow this diff --git a/tests/compiler/comma.wast b/tests/compiler/comma.wast new file mode 100644 index 00000000..d31e4383 --- /dev/null +++ b/tests/compiler/comma.wast @@ -0,0 +1,294 @@ +(module + (type $v (func)) + (global $comma/a (mut i32) (i32.const 0)) + (global $comma/b (mut i32) (i32.const 0)) + (global $HEAP_BASE i32 (i32.const 4)) + (memory $0 1) + (export "memory" (memory $0)) + (start $start) + (func $start (; 0 ;) (type $v) + (local $0 i32) + (local $1 i32) + (block + (set_global $comma/b + (block (result i32) + (set_local $0 + (get_global $comma/a) + ) + (set_global $comma/a + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (drop + (get_global $comma/a) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/a) + (i32.const 1) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/b) + (i32.const 0) + ) + ) + (unreachable) + ) + (block + (drop + (block (result i32) + (set_local $0 + (get_global $comma/a) + ) + (set_global $comma/a + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (set_global $comma/b + (get_global $comma/a) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/a) + (i32.const 2) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/b) + (i32.const 2) + ) + ) + (unreachable) + ) + (set_global $comma/a + (block (result i32) + (set_global $comma/b + (i32.const 0) + ) + (get_global $comma/b) + ) + ) + (set_global $comma/b + (block (result i32) + (drop + (block (result i32) + (set_local $0 + (get_global $comma/a) + ) + (set_global $comma/a + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (get_global $comma/a) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/a) + (i32.const 1) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/b) + (i32.const 1) + ) + ) + (unreachable) + ) + (set_global $comma/a + (block (result i32) + (drop + (block (result i32) + (set_local $0 + (get_global $comma/a) + ) + (set_global $comma/a + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (block (result i32) + (set_global $comma/b + (get_global $comma/a) + ) + (get_global $comma/b) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/a) + (i32.const 2) + ) + ) + (unreachable) + ) + (if + (i32.eqz + (i32.eq + (get_global $comma/b) + (i32.const 2) + ) + ) + (unreachable) + ) + (block $break|0 + (block + (set_local $1 + (i32.const 0) + ) + ) + (loop $continue|0 + (if + (i32.lt_u + (get_local $1) + (get_global $comma/a) + ) + (block + (nop) + (block + (drop + (block (result i32) + (set_local $0 + (get_global $comma/a) + ) + (set_global $comma/a + (i32.sub + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + (drop + (block (result i32) + (set_local $0 + (get_local $1) + ) + (set_local $1 + (i32.add + (get_local $0) + (i32.const 1) + ) + ) + (get_local $0) + ) + ) + ) + (br $continue|0) + ) + ) + ) + ) + (if + (i32.eqz + (i32.eq + (get_local $1) + (i32.const 1) + ) + ) + (unreachable) + ) + (block + (drop + (i32.const 1) + ) + (drop + (i32.const 2) + ) + (drop + (i32.const 3) + ) + ) + ) +) +(; +[program.elements] + GLOBAL: NaN + GLOBAL: Infinity + FUNCTION_PROTOTYPE: isNaN + FUNCTION_PROTOTYPE: isFinite + FUNCTION_PROTOTYPE: clz + FUNCTION_PROTOTYPE: ctz + FUNCTION_PROTOTYPE: popcnt + FUNCTION_PROTOTYPE: rotl + FUNCTION_PROTOTYPE: rotr + FUNCTION_PROTOTYPE: abs + FUNCTION_PROTOTYPE: max + FUNCTION_PROTOTYPE: min + FUNCTION_PROTOTYPE: ceil + FUNCTION_PROTOTYPE: floor + FUNCTION_PROTOTYPE: copysign + FUNCTION_PROTOTYPE: nearest + FUNCTION_PROTOTYPE: reinterpret + FUNCTION_PROTOTYPE: sqrt + FUNCTION_PROTOTYPE: trunc + FUNCTION_PROTOTYPE: load + FUNCTION_PROTOTYPE: store + FUNCTION_PROTOTYPE: sizeof + FUNCTION_PROTOTYPE: select + FUNCTION_PROTOTYPE: unreachable + FUNCTION_PROTOTYPE: current_memory + FUNCTION_PROTOTYPE: grow_memory + FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: parseFloat + FUNCTION_PROTOTYPE: changetype + FUNCTION_PROTOTYPE: assert + FUNCTION_PROTOTYPE: i8 + FUNCTION_PROTOTYPE: i16 + FUNCTION_PROTOTYPE: i32 + FUNCTION_PROTOTYPE: i64 + FUNCTION_PROTOTYPE: u8 + FUNCTION_PROTOTYPE: u16 + FUNCTION_PROTOTYPE: u32 + FUNCTION_PROTOTYPE: u64 + FUNCTION_PROTOTYPE: bool + FUNCTION_PROTOTYPE: f32 + FUNCTION_PROTOTYPE: f64 + FUNCTION_PROTOTYPE: isize + FUNCTION_PROTOTYPE: usize + GLOBAL: HEAP_BASE + GLOBAL: comma/a + GLOBAL: comma/b +[program.exports] + +;) diff --git a/tests/compiler/std/array.wast b/tests/compiler/std/array.wast index 802551c7..cf844f2a 100644 --- a/tests/compiler/std/array.wast +++ b/tests/compiler/std/array.wast @@ -51,6 +51,8 @@ GLOBAL: HEAP_BASE CLASS_PROTOTYPE: std:array/Array CLASS_PROTOTYPE: Array + CLASS_PROTOTYPE: std:array/CArray + CLASS_PROTOTYPE: CArray CLASS_PROTOTYPE: std:error/Error CLASS_PROTOTYPE: Error CLASS_PROTOTYPE: std:error/RangeError @@ -79,6 +81,7 @@ FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator [program.exports] CLASS_PROTOTYPE: std:array/Array + CLASS_PROTOTYPE: std:array/CArray CLASS_PROTOTYPE: std:error/Error CLASS_PROTOTYPE: std:error/RangeError CLASS_PROTOTYPE: std:heap/Heap diff --git a/tests/compiler/std/heap.wast b/tests/compiler/std/heap.wast index 08132d0a..ebdcaa69 100644 --- a/tests/compiler/std/heap.wast +++ b/tests/compiler/std/heap.wast @@ -2600,6 +2600,8 @@ GLOBAL: HEAP_BASE CLASS_PROTOTYPE: std:array/Array CLASS_PROTOTYPE: Array + CLASS_PROTOTYPE: std:array/CArray + CLASS_PROTOTYPE: CArray CLASS_PROTOTYPE: std:error/Error CLASS_PROTOTYPE: Error CLASS_PROTOTYPE: std:error/RangeError @@ -2632,6 +2634,7 @@ GLOBAL: std/heap/i [program.exports] CLASS_PROTOTYPE: std:array/Array + CLASS_PROTOTYPE: std:array/CArray CLASS_PROTOTYPE: std:error/Error CLASS_PROTOTYPE: std:error/RangeError CLASS_PROTOTYPE: std:heap/Heap