diff --git a/src/ast.ts b/src/ast.ts index 305e0f97..70c7bd0b 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -38,9 +38,9 @@ export enum NodeKind { // statements BLOCK, BREAK, + CASE, CLASS, // is also declaration CONTINUE, - DECORATOR, DO, EMPTY, ENUM, // is also declaration @@ -64,7 +64,12 @@ export enum NodeKind { TRY, VARIABLE, // wraps declarations VARIABLEDECLARATION, - WHILE + WHILE, + + // other + DECORATOR, + MODIFIER, + PARAMETER } /** Base class of all nodes. */ @@ -246,7 +251,7 @@ export abstract class Node { const expr: UnaryPostfixExpression = new UnaryPostfixExpression(); expr.range = range; expr.operator = operator; - (expr.expression = expression).parent = expr; + (expr.operand = expression).parent = expr; return expr; } @@ -254,7 +259,7 @@ export abstract class Node { const expr: UnaryPrefixExpression = new UnaryPrefixExpression(); expr.range = range; expr.operator = operator; - (expr.expression = expression).parent = expr; + (expr.operand = expression).parent = expr; return expr; } @@ -278,7 +283,7 @@ export abstract class Node { const stmt: ClassDeclaration = new ClassDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt; if (stmt.extendsType = extendsType) (extendsType).parent = stmt; for (i = 0, k = (stmt.implementsTypes = implementsTypes).length; i < k; ++i) implementsTypes[i].parent = stmt; @@ -298,7 +303,7 @@ export abstract class Node { static createDecorator(expression: Expression, args: Expression[], range: Range): Decorator { const stmt: Decorator = new Decorator(); stmt.range = range; - (stmt.expression = expression).parent = stmt; + (stmt.name = expression).parent = stmt; for (let i: i32 = 0, k: i32 = (stmt.arguments = args).length; i < k; ++i) args[i].parent = stmt; return stmt; } @@ -321,8 +326,8 @@ export abstract class Node { const stmt: EnumDeclaration = new EnumDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; - for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt; + (stmt.name = identifier).parent = stmt; + for (i = 0, k = (stmt.values = members).length; i < k; ++i) members[i].parent = stmt; if (stmt.modifiers = modifiers) for (i = 0, k = (modifiers).length; i < k; ++i) (modifiers)[i].parent = stmt; if (stmt.decorators = decorators) for (i = 0, k = (decorators).length; i < k; ++i) (decorators)[i].parent = stmt; return stmt; @@ -331,7 +336,7 @@ export abstract class Node { static createEnumValue(identifier: IdentifierExpression, value: Expression | null, range: Range): EnumValueDeclaration { const stmt: EnumValueDeclaration = new EnumValueDeclaration(); stmt.range = range; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; if (stmt.value = value) (value).parent = stmt; return stmt; } @@ -352,7 +357,7 @@ export abstract class Node { const stmt: ExportImportStatement = new ExportImportStatement(); stmt.range = range; (stmt.identifier = identifier).parent = stmt; - (stmt.asIdentifier = asIdentifier).parent = stmt; + (stmt.externalIdentifier = asIdentifier).parent = stmt; return stmt; } @@ -376,8 +381,8 @@ export abstract class Node { const stmt: IfStatement = new IfStatement(); stmt.range = range; (stmt.condition = condition).parent = stmt; - (stmt.statement = statement).parent = stmt; - if (stmt.elseStatement = elseStatement) (elseStatement).parent = stmt; + (stmt.ifTrue = statement).parent = stmt; + if (stmt.ifFalse = elseStatement) (elseStatement).parent = stmt; return stmt; } @@ -394,7 +399,7 @@ export abstract class Node { static createImportDeclaration(externalIdentifier: IdentifierExpression, identifier: IdentifierExpression | null, range: Range): ImportDeclaration { const elem: ImportDeclaration = new ImportDeclaration(); elem.range = range; - (elem.identifier = identifier ? identifier : externalIdentifier).parent = elem; + (elem.name = identifier ? identifier : externalIdentifier).parent = elem; (elem.externalIdentifier = externalIdentifier).parent = elem; return elem; } @@ -403,7 +408,7 @@ export abstract class Node { const stmt: InterfaceDeclaration = new InterfaceDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; if (stmt.extendsType = extendsType) (extendsType).parent = stmt; for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt; if (stmt.modifiers = modifiers) for (i = 0, k = (modifiers).length; i < k; ++i) (modifiers)[i].parent = stmt; @@ -414,7 +419,7 @@ export abstract class Node { const stmt: FieldDeclaration = new FieldDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; if (stmt.type = type) (type).parent = stmt; if (stmt.initializer = initializer) (initializer).parent = stmt; if (stmt.modifiers = modifiers) for (i = 0, k = (modifiers).length; i < k; ++i) (modifiers)[i].parent = stmt; @@ -440,13 +445,13 @@ export abstract class Node { return elem; } - static createParameter(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, multiple: bool, range: Range): Parameter { + static createParameter(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, isRest: bool, range: Range): Parameter { const elem: Parameter = new Parameter(); elem.range = range; - (elem.identifier = identifier).parent = elem; + (elem.name = identifier).parent = elem; if (elem.type = type) (type).parent = elem; if (elem.initializer = initializer) (initializer).parent = elem; - elem.multiple = multiple; + elem.isRest = isRest; return elem; } @@ -454,7 +459,7 @@ export abstract class Node { const stmt: FunctionDeclaration = new FunctionDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt; for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt; if (stmt.returnType = returnType) (returnType).parent = stmt; @@ -468,7 +473,7 @@ export abstract class Node { const stmt: MethodDeclaration = new MethodDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt; for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt; if (stmt.returnType = returnType) (returnType).parent = stmt;; @@ -489,7 +494,7 @@ export abstract class Node { const stmt: NamespaceDeclaration = new NamespaceDeclaration(); stmt.range = range; let i: i32, k: i32; - (stmt.identifier = identifier).parent = stmt; + (stmt.name = identifier).parent = stmt; for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt; if (stmt.modifiers = modifiers) for (i = 0, k = (modifiers).length; i < k; ++i) (modifiers)[i].parent = stmt; if (stmt.decorators = decorators) for (i = 0, k = (decorators).length; i < k; ++i) (decorators)[i].parent = stmt; @@ -499,14 +504,14 @@ export abstract class Node { static createReturn(expression: Expression | null, range: Range): ReturnStatement { const stmt: ReturnStatement = new ReturnStatement(); stmt.range = range; - if (stmt.expression = expression) (expression).parent = stmt; + if (stmt.value = expression) (expression).parent = stmt; return stmt; } static createSwitch(expression: Expression, cases: SwitchCase[], range: Range): SwitchStatement { const stmt: SwitchStatement = new SwitchStatement(); stmt.range = range; - (stmt.expression = expression).parent = stmt; + (stmt.condition = expression).parent = stmt; for (let i: i32 = 0, k: i32 = (stmt.cases = cases).length; i < k; ++i) cases[i].parent = stmt; return stmt; } @@ -522,7 +527,7 @@ export abstract class Node { static createThrow(expression: Expression, range: Range): ThrowStatement { const stmt: ThrowStatement = new ThrowStatement(); stmt.range = range; - (stmt.expression = expression).parent = stmt; + (stmt.value = expression).parent = stmt; return stmt; } @@ -550,7 +555,7 @@ export abstract class Node { static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableDeclaration { const elem: VariableDeclaration = new VariableDeclaration(); elem.range = range; - (elem.identifier = identifier).parent = elem; + (elem.name = identifier).parent = elem; if (elem.type = type) (type).parent = elem; if (elem.initializer = initializer) (initializer).parent = elem; elem.modifiers = modifiers; @@ -621,9 +626,12 @@ export class TypeParameter extends Node { /** Base class of all expression nodes. */ export abstract class Expression extends Node { } +/** Represents an identifier expression. */ export class IdentifierExpression extends Expression { kind = NodeKind.IDENTIFIER; + + /** Textual name. */ name: string; serialize(sb: string[]): void { @@ -631,6 +639,7 @@ export class IdentifierExpression extends Expression { } } +/** Indicates the kind of a literal. */ export const enum LiteralKind { FLOAT, INTEGER, @@ -640,14 +649,22 @@ export const enum LiteralKind { OBJECT } +/** Base class of all literal expressions. */ export abstract class LiteralExpression extends Expression { + kind = NodeKind.LITERAL; + + /** Specific literal kind. */ literalKind: LiteralKind; } +/** Represents an `[]` literal expression. */ export class ArrayLiteralExpression extends LiteralExpression { + // kind = NodeKind.LITERAL literalKind = LiteralKind.ARRAY; + + /** Nested element expressions. */ elementExpressions: (Expression | null)[]; serialize(sb: string[]): void { @@ -662,16 +679,22 @@ export class ArrayLiteralExpression extends LiteralExpression { } } +/** Indicates the kind of an assertion. */ export const enum AssertionKind { PREFIX, AS } +/** Represents an assertion expression. */ export class AssertionExpression extends Expression { kind = NodeKind.ASSERTION; + + /** Specific kind of this assertion. */ assertionKind: AssertionKind; + /** Expression being asserted. */ expression: Expression; + /** Target type. */ toType: TypeNode; serialize(sb: string[]): void { @@ -688,11 +711,16 @@ export class AssertionExpression extends Expression { } } +/** Represents a binary expression. */ export class BinaryExpression extends Expression { kind = NodeKind.BINARY; + + /** Operator token. */ operator: Token; + /** Left-hand side expression */ left: Expression; + /** Right-hand side expression. */ right: Expression; serialize(sb: string[]): void { @@ -704,11 +732,16 @@ export class BinaryExpression extends Expression { } } +/** Represents a call expression. */ export class CallExpression extends Expression { kind = NodeKind.CALL; + + /** Called expression. Usually an identifier or property access expression. */ expression: Expression; + /** Provided type arguments. */ typeArguments: TypeNode[]; + /** Provided arguments. */ arguments: Expression[]; serialize(sb: string[]): void { @@ -733,15 +766,20 @@ export class CallExpression extends Expression { } } +/** Represents a `constructor` expression. */ export class ConstructorExpression extends IdentifierExpression { kind = NodeKind.CONSTRUCTOR; name = "this"; } +/** Represents an element access expression, e.g., array access. */ export class ElementAccessExpression extends Expression { kind = NodeKind.ELEMENTACCESS; + + /** Expression being accessed. */ expression: Expression; + /** Element of the expression being accessed. */ elementExpression: Expression; serialize(sb: string[]): void { @@ -752,9 +790,13 @@ export class ElementAccessExpression extends Expression { } } +/** Represents a float literal expression. */ export class FloatLiteralExpression extends LiteralExpression { + // kind = NodeKind.LITERAL literalKind = LiteralKind.FLOAT; + + /** Float value. */ value: f64; serialize(sb: string[]): void { @@ -762,9 +804,13 @@ export class FloatLiteralExpression extends LiteralExpression { } } +/** Represents an integer literal expression. */ export class IntegerLiteralExpression extends LiteralExpression { + // kind = NodeKind.LITERAL literalKind = LiteralKind.INTEGER; + + /** Integer value. */ value: I64; serialize(sb: string[]): void { @@ -772,6 +818,7 @@ export class IntegerLiteralExpression extends LiteralExpression { } } +/** Represents a `new` expression. Like a call but with its own kind. */ export class NewExpression extends CallExpression { kind = NodeKind.NEW; @@ -782,14 +829,18 @@ export class NewExpression extends CallExpression { } } +/** Represents a `null` expression. */ export class NullExpression extends IdentifierExpression { kind = NodeKind.NULL; name = "null"; } +/** Represents a parenthesized expression. */ export class ParenthesizedExpression extends Expression { kind = NodeKind.PARENTHESIZED; + + /** Expression in parenthesis. */ expression: Expression; serialize(sb: string[]): void { @@ -799,10 +850,14 @@ export class ParenthesizedExpression extends Expression { } } +/** Represents a property access expression. */ export class PropertyAccessExpression extends Expression { kind = NodeKind.PROPERTYACCESS; + + /** Expression being accessed. */ expression: Expression; + /** Property of the expression being accessed. */ property: IdentifierExpression; serialize(sb: string[]): void { @@ -812,9 +867,13 @@ export class PropertyAccessExpression extends Expression { } } +/** Represents a regular expression literal expression. */ export class RegexpLiteralExpression extends LiteralExpression { + // kind = NodeKind.LITERAL literalKind = LiteralKind.REGEXP; + + /** Value of the expression. */ value: string; serialize(sb: string[]): void { @@ -822,11 +881,16 @@ export class RegexpLiteralExpression extends LiteralExpression { } } +/** Represents a ternary expression, i.e., short if notation. */ export class TernaryExpression extends Expression { kind = NodeKind.TERNARY; + + /** Condition expression. */ condition: Expression; + /** Expression executed when condition is `true`. */ ifThen: Expression; + /** Expression executed when condition is `false`. */ ifElse: Expression; serialize(sb: string[]): void { @@ -838,9 +902,12 @@ export class TernaryExpression extends Expression { } } +/** Represents a string literal expression. */ export class StringLiteralExpression extends LiteralExpression { literalKind = LiteralKind.STRING; + + /** String value without quotes. */ value: string; serialize(sb: string[]): void { @@ -848,37 +915,48 @@ export class StringLiteralExpression extends LiteralExpression { } } +/** Represents a `super` expression. */ export class SuperExpression extends IdentifierExpression { kind = NodeKind.SUPER; name = "super"; } +/** Represents a `this` expression. */ export class ThisExpression extends IdentifierExpression { kind = NodeKind.THIS; name = "this"; } +/** Represents a `true` expression. */ export class TrueExpression extends IdentifierExpression { kind = NodeKind.TRUE; name = "true"; } +/** Represents a `false` expression. */ export class FalseExpression extends IdentifierExpression { kind = NodeKind.FALSE; name = "false"; } +/** Base class of all unary expressions. */ export abstract class UnaryExpression extends Expression { + + // kind varies + + /** Operator token. */ operator: Token; - expression: Expression; + /** Operand expression. */ + operand: Expression; } +/** Represents a unary postfix expression, e.g. a postfix increment. */ export class UnaryPostfixExpression extends UnaryExpression { kind = NodeKind.UNARYPOSTFIX; serialize(sb: string[]): void { - this.expression.serialize(sb); + this.operand.serialize(sb); switch (this.operator) { case Token.PLUS_PLUS: sb.push("++"); break; case Token.MINUS_MINUS: sb.push("--"); break; @@ -887,18 +965,20 @@ export class UnaryPostfixExpression extends UnaryExpression { } } +/** Represents a unary prefix expression, e.g. a negation. */ export class UnaryPrefixExpression extends UnaryExpression { kind = NodeKind.UNARYPREFIX; serialize(sb: string[]): void { sb.push(operatorTokenToString(this.operator)); - this.expression.serialize(sb); + this.operand.serialize(sb); } } // statements +/** Indicates the specific kind of a modifier. */ export enum ModifierKind { ASYNC, CONST, @@ -918,19 +998,28 @@ export enum ModifierKind { /** Base class of all statement nodes. */ export abstract class Statement extends Node { } +/** A top-level source node. */ export class Source extends Node { kind = NodeKind.SOURCE; parent = null; - path: string; - normalizedPath: string; - internalPath: string; - statements: Statement[]; + /** Path as provided to the parser. */ + path: string; + /** Normalized path. */ + normalizedPath: string; + /** Path used internally. */ + internalPath: string; + /** Contained statements. */ + statements: Statement[]; + /** Full source text. */ text: string; + /** Tokenizer reference. */ tokenizer: Tokenizer | null = null; + /** Whether an entry file or not. */ isEntry: bool; + /** Constructs a new source node. */ constructor(path: string, text: string, isEntry: bool = false) { super(); this.path = path; @@ -942,8 +1031,6 @@ export class Source extends Node { this.isEntry = isEntry; } - get isDeclaration(): bool { return !this.isEntry && this.path.endsWith(".d.ts"); } - serialize(sb: string[]): void { for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) { const statement: Statement = this.statements[i]; @@ -957,25 +1044,41 @@ export class Source extends Node { } } +/** Base class of all declaration statements. */ export abstract class DeclarationStatement extends Statement { - identifier: IdentifierExpression; + // kind varies + + /** Simple name being declared. */ + name: IdentifierExpression; + /** Array of modifiers. */ modifiers: Modifier[] | null; + /** Array of decorators. */ decorators: Decorator[] | null = null; protected _cachedInternalName: string | null = null; + /** Gets the mangled internal name of this declaration. */ get internalName(): string { return this._cachedInternalName === null ? this._cachedInternalName = mangleInternalName(this) : this._cachedInternalName; } } +/** Base class of all variable-like declaration statements with a type and initializer. */ export abstract class VariableLikeDeclarationStatement extends DeclarationStatement { + + // kind varies + + /** Variable type. */ type: TypeNode | null; + /** Variable initializer. */ initializer: Expression | null; } +/** Represents a block statement. */ export class BlockStatement extends Statement { kind = NodeKind.BLOCK; + + /** Contained statements. */ statements: Statement[]; serialize(sb: string[]): void { @@ -991,9 +1094,12 @@ export class BlockStatement extends Statement { } } +/** Represents a `break` statement. */ export class BreakStatement extends Statement { kind = NodeKind.BREAK; + + /** Target label, if applicable. */ label: IdentifierExpression | null; serialize(sb: string[]): void { @@ -1005,19 +1111,19 @@ export class BreakStatement extends Statement { } } +/** Represents a `class` declaration. */ export class ClassDeclaration extends DeclarationStatement { kind = NodeKind.CLASS; - typeParameters: TypeParameter[]; - extendsType: TypeNode | null; - implementsTypes: TypeNode[]; - members: DeclarationStatement[]; - get internalName(): string { - if (this._cachedInternalName !== null) - return this._cachedInternalName; - return this._cachedInternalName = mangleInternalName(this); - } + /** Accepted type parameters. */ + typeParameters: TypeParameter[]; + /** Base class type being extended. */ + extendsType: TypeNode | null; + /** Interface types being implemented. */ + implementsTypes: TypeNode[]; + /** Class member declarations. */ + members: DeclarationStatement[]; serialize(sb: string[]): void { let i: i32, k: i32; @@ -1032,7 +1138,7 @@ export class ClassDeclaration extends DeclarationStatement { sb.push(" "); } sb.push("class "); - sb.push(this.identifier.name); + sb.push(this.name.name); if (this.typeParameters.length) { sb.push("<"); for (i = 0, k = this.typeParameters.length; i < k; ++i) { @@ -1066,9 +1172,12 @@ export class ClassDeclaration extends DeclarationStatement { } } +/** Represents a `continue` statement. */ export class ContinueStatement extends Statement { kind = NodeKind.CONTINUE; + + /** Target label, if applicable. */ label: IdentifierExpression | null; serialize(sb: string[]): void { @@ -1080,15 +1189,19 @@ export class ContinueStatement extends Statement { } } +/** Depresents a decorator. */ export class Decorator extends Statement { kind = NodeKind.DECORATOR; - expression: Expression; + + /** Name expression. */ + name: Expression; + /** Argument expressions. */ arguments: Expression[]; serialize(sb: string[]): void { sb.push("@"); - this.expression.serialize(sb); + this.name.serialize(sb); sb.push("("); for (let i: i32 = 0, k: i32 = this.arguments.length; i < k; ++i) { if (i > 0) @@ -1099,10 +1212,14 @@ export class Decorator extends Statement { } } +/** Represents a `do` statement. */ export class DoStatement extends Statement { kind = NodeKind.DO; + + /** Statement being looped over. */ statement: Statement; + /** Condition when to repeat. */ condition: Expression; serialize(sb: string[]): void { @@ -1117,6 +1234,7 @@ export class DoStatement extends Statement { } } +/** Represents an empty statement, i.e., a semicolon terminating nothing. */ export class EmptyStatement extends Statement { kind = NodeKind.EMPTY; @@ -1124,10 +1242,13 @@ export class EmptyStatement extends Statement { serialize(sb: string[]): void {} } +/** Represents an `enum` declaration. */ export class EnumDeclaration extends DeclarationStatement { kind = NodeKind.ENUM; - members: EnumValueDeclaration[]; + + /** Enum value declarations. */ + values: EnumValueDeclaration[]; serialize(sb: string[]): void { let i: i32, k: i32; @@ -1137,25 +1258,29 @@ export class EnumDeclaration extends DeclarationStatement { sb.push(" "); } sb.push("enum "); - this.identifier.serialize(sb); + this.name.serialize(sb); sb.push(" {\n"); - for (i = 0, k = this.members.length; i < k; ++i) { + for (i = 0, k = this.values.length; i < k; ++i) { if (i > 0) sb.push(",\n"); - this.members[i].serialize(sb); + this.values[i].serialize(sb); } sb.push("\n}"); } } +/** Represents a value of an `enum` declaration. */ export class EnumValueDeclaration extends DeclarationStatement { kind = NodeKind.ENUMVALUE; modifiers = null; + // name is inherited + + /** Value expression. */ value: Expression | null; serialize(sb: string[]): void { - this.identifier.serialize(sb); + this.name.serialize(sb); if (this.value) { sb.push(" = "); (this.value).serialize(sb); @@ -1163,24 +1288,32 @@ export class EnumValueDeclaration extends DeclarationStatement { } } +/** Represents an `export import` statement of an interface. */ export class ExportImportStatement extends Node { kind = NodeKind.EXPORTIMPORT; + + /** Identifier being imported. */ identifier: IdentifierExpression; - asIdentifier: IdentifierExpression; + /** Identifier being exported. */ + externalIdentifier: IdentifierExpression; serialize(sb: string[]): void { sb.push("export import "); - this.asIdentifier.serialize(sb); + this.externalIdentifier.serialize(sb); sb.push(" = "); this.identifier.serialize(sb); } } +/** Represents a member of an `export` statement. */ export class ExportMember extends Node { kind = NodeKind.EXPORTMEMBER; + + /** Identifier being exported. */ identifier: IdentifierExpression; + /** Identifier seen when imported again. */ externalIdentifier: IdentifierExpression; serialize(sb: string[]): void { @@ -1192,13 +1325,20 @@ export class ExportMember extends Node { } } +/** Represents an `export` statement. */ export class ExportStatement extends Statement { kind = NodeKind.EXPORT; + + /** Array of modifiers. */ modifiers: Modifier[] | null; + /** Array of members. */ members: ExportMember[]; + /** Path being exported from, if applicable. */ path: StringLiteralExpression | null; + /** Normalized path, if `path` is set. */ normalizedPath: string | null; + /** Mangled internal path being referenced, if `path` is set. */ internalPath: string | null; serialize(sb: string[]): void { @@ -1222,9 +1362,12 @@ export class ExportStatement extends Statement { } } +/** Represents an expression statement, i.e., an expression being used as a statement */ export class ExpressionStatement extends Statement { kind = NodeKind.EXPRESSION; + + /** Expression being used as a statement.*/ expression: Expression; serialize(sb: string[]): void { @@ -1232,6 +1375,7 @@ export class ExpressionStatement extends Statement { } } +/** Represents a field declaration within a `class`. */ export class FieldDeclaration extends VariableLikeDeclarationStatement { kind = NodeKind.FIELD; @@ -1248,7 +1392,7 @@ export class FieldDeclaration extends VariableLikeDeclarationStatement { (this.modifiers)[i].serialize(sb); sb.push(" "); } - this.identifier.serialize(sb); + this.name.serialize(sb); if (this.type) { sb.push(": "); (this.type).serialize(sb); @@ -1260,12 +1404,18 @@ export class FieldDeclaration extends VariableLikeDeclarationStatement { } } +/** Represents a `for` statement. */ export class ForStatement extends Statement { kind = NodeKind.FOR; + + /** Initializer statement, if present. Either a {@link VariableStatement} or {@link ExpressionStatement}. */ initializer: Statement | null; + /** Condition expression, if present. */ condition: Expression | null; + /** Incrementor expression, if present. */ incrementor: Expression | null; + /** Statement being looped over. */ statement: Statement; serialize(sb: string[]): void { @@ -1287,19 +1437,19 @@ export class ForStatement extends Statement { } } +/** Represents a `function` declaration. */ export class FunctionDeclaration extends DeclarationStatement { kind = NodeKind.FUNCTION; - typeParameters: TypeParameter[]; - parameters: Parameter[]; - returnType: TypeNode | null; - statements: Statement[] | null; - get internalName(): string { - if (this._cachedInternalName !== null) - return this._cachedInternalName; - return this._cachedInternalName = mangleInternalName(this); - } + /** Accepted type parameters. */ + typeParameters: TypeParameter[]; + /** Accepted parameters. */ + parameters: Parameter[]; + /** Return type. */ + returnType: TypeNode | null; + /** Contained statements. */ + statements: Statement[] | null; serialize(sb: string[]): void { let i: i32, k: i32; @@ -1318,7 +1468,7 @@ export class FunctionDeclaration extends DeclarationStatement { } protected serializeCommon(sb: string[]): void { - this.identifier.serialize(sb); + this.name.serialize(sb); let i: i32, k: i32; if (this.typeParameters.length) { sb.push("<"); @@ -1355,51 +1505,65 @@ export class FunctionDeclaration extends DeclarationStatement { } } +/** Represents an `if` statement. */ export class IfStatement extends Statement { kind = NodeKind.IF; + + /** Condition. */ condition: Expression; - statement: Statement; - elseStatement: Statement | null; + /** Statement executed when condition is `true`. */ + ifTrue: Statement; + /** Statement executed when condition is `false`. */ + ifFalse: Statement | null; serialize(sb: string[]): void { sb.push("if ("); this.condition.serialize(sb); sb.push(") "); - this.statement.serialize(sb); - if (this.statement.kind != NodeKind.BLOCK) + this.ifTrue.serialize(sb); + if (this.ifTrue.kind != NodeKind.BLOCK) sb.push(";\n"); - if (this.elseStatement) { - if (this.statement.kind == NodeKind.BLOCK) + if (this.ifFalse) { + if (this.ifTrue.kind == NodeKind.BLOCK) sb.push(" else "); else sb.push("else "); - (this.elseStatement).serialize(sb); + (this.ifFalse).serialize(sb); } } } +/** Represents an `import` declaration, a single member within an {@link ImportStatement}. */ export class ImportDeclaration extends DeclarationStatement { kind = NodeKind.IMPORTDECLARATION; modifiers = null; + + /** Identifier being imported. */ externalIdentifier: IdentifierExpression; serialize(sb: string[]): void { this.externalIdentifier.serialize(sb); - if (this.externalIdentifier != this.identifier) { + if (this.externalIdentifier != this.name) { sb.push(" as "); - (this.identifier).serialize(sb); + (this.name).serialize(sb); } } } +/** Represents an `import` statement. */ export class ImportStatement extends Statement { kind = NodeKind.IMPORT; + + /** Array of member declarations. */ declarations: ImportDeclaration[]; + /** Path being imported from. */ path: StringLiteralExpression; + /** Normalized path. */ normalizedPath: string; + /** Mangled internal path being referenced. */ internalPath: string; serialize(sb: string[]): void { @@ -1414,6 +1578,7 @@ export class ImportStatement extends Statement { } } +/** Represents an `interfarce` declaration. */ export class InterfaceDeclaration extends ClassDeclaration { kind = NodeKind.INTERFACE; @@ -1431,7 +1596,7 @@ export class InterfaceDeclaration extends ClassDeclaration { sb.push(" "); } sb.push("interface "); - this.identifier.serialize(sb); + this.name.serialize(sb); if (this.typeParameters.length) { sb.push("<"); for (i = 0, k = this.typeParameters.length; i < k; ++i) { @@ -1457,6 +1622,7 @@ export class InterfaceDeclaration extends ClassDeclaration { } } +/** Represents a method declaration within a `class`. */ export class MethodDeclaration extends FunctionDeclaration { kind = NodeKind.METHOD; @@ -1477,9 +1643,12 @@ export class MethodDeclaration extends FunctionDeclaration { } } +/** Represents a `namespace` declaration. */ export class NamespaceDeclaration extends DeclarationStatement { kind = NodeKind.NAMESPACE; + + /** Array of namespace members. */ members: Statement[]; serialize(sb: string[]): void { @@ -1495,7 +1664,7 @@ export class NamespaceDeclaration extends DeclarationStatement { sb.push(" "); } sb.push("namespace "); - this.identifier.serialize(sb); + this.name.serialize(sb); sb.push(" {\n"); for (i = 0, k = this.members.length; i < k; ++i) { this.members[i].serialize(sb); @@ -1508,17 +1677,24 @@ export class NamespaceDeclaration extends DeclarationStatement { } } +/** Represents a function parameter. */ export class Parameter extends Node { - identifier: IdentifierExpression; + kind = NodeKind.PARAMETER; + + /** Parameter name. */ + name: IdentifierExpression; + /** Parameter type. */ type: TypeNode | null; + /** Initializer expression, if present. */ initializer: Expression | null; - multiple: bool; + /** Whether a rest parameter or not. */ + isRest: bool; serialize(sb: string[]): void { - if (this.multiple) + if (this.isRest) sb.push("..."); - this.identifier.serialize(sb); + this.name.serialize(sb); if (this.type) { sb.push(": "); (this.type).serialize(sb); @@ -1530,14 +1706,19 @@ export class Parameter extends Node { } } +/** Represents a single modifier. */ export class Modifier extends Node { + kind = NodeKind.MODIFIER; + + /** Specific modifier kind. */ modifierKind: ModifierKind; serialize(sb: string[]): void { sb.push(this.toString()); } + /** Returns the TypeScript representation of this modifier. */ toString(): string { switch (this.modifierKind) { case ModifierKind.ABSTRACT: return "abstract"; @@ -1553,28 +1734,36 @@ export class Modifier extends Node { case ModifierKind.READONLY: return "readonly"; case ModifierKind.SET: return "set"; case ModifierKind.STATIC: return "static"; - default: return "INVALID_MODIFIER"; + default: assert(false); return ""; } } } +/** Represents a `return` statement. */ export class ReturnStatement extends Statement { kind = NodeKind.RETURN; - expression: Expression | null; + + /** Value expression being returned, if present. */ + value: Expression | null; serialize(sb: string[]): void { - if (this.expression) { + if (this.value) { sb.push("return "); - (this.expression).serialize(sb); + (this.value).serialize(sb); } else sb.push("return"); } } +/** Represents a single `case` within a `switch` statement. */ export class SwitchCase extends Node { - label: Expression | null; // null := default + kind = NodeKind.CASE; + + /** Label expression. `null` indicates the default case. */ + label: Expression | null; + /** Contained statements. */ statements: Statement[]; serialize(sb: string[]): void { @@ -1596,15 +1785,19 @@ export class SwitchCase extends Node { } } +/** Represents a `switch` statement. */ export class SwitchStatement extends Statement { kind = NodeKind.SWITCH; - expression: Expression; + + /** Condition expression. */ + condition: Expression; + /** Contained cases. */ cases: SwitchCase[]; serialize(sb: string[]): void { sb.push("switch ("); - this.expression.serialize(sb); + this.condition.serialize(sb); sb.push(") {\n"); for (let i: i32 = 0, k: i32 = this.cases.length; i < k; ++i) { this.cases[i].serialize(sb); @@ -1614,24 +1807,33 @@ export class SwitchStatement extends Statement { } } +/** Represents a `throw` statement. */ export class ThrowStatement extends Statement { kind = NodeKind.THROW; - expression: Expression; + + /** Value expression being thrown. */ + value: Expression; serialize(sb: string[]): void { sb.push("throw "); - this.expression.serialize(sb); + this.value.serialize(sb); sb.push(";"); } } +/** Represents a `try` statement. */ export class TryStatement extends Statement { kind = NodeKind.TRY; + + /** Contained statements. */ statements: Statement[]; + /** Variable identifier for a caught exception, if a `catch` clause is present. */ catchVariable: IdentifierExpression | null; + /** Statements being executed when an exception has been caught, if a `catch` clause is present. */ catchStatements: Statement[] | null; + /** Statements being executed in any case, if a `finally` clause is present. */ finallyStatements: Statement[] | null; serialize(sb: string[]): void { @@ -1662,13 +1864,16 @@ export class TryStatement extends Statement { } } +/** Represents a single variable declaration within a {@link VariableStatement}. */ export class VariableDeclaration extends VariableLikeDeclarationStatement { kind = NodeKind.VARIABLEDECLARATION; + + /** Array of modifiers. */ modifiers: Modifier[] | null; serialize(sb: string[]): void { - this.identifier.serialize(sb); + this.name.serialize(sb); if (this.type) { sb.push(": "); (this.type).serialize(sb); @@ -1680,11 +1885,16 @@ export class VariableDeclaration extends VariableLikeDeclarationStatement { } } +/** Represents a variable statement, i.e., a `var`, `let` or `const` statement. */ export class VariableStatement extends Statement { kind = NodeKind.VARIABLE; + + /** Array of modifiers. */ modifiers: Modifier[] | null; + /** Array of decorators. */ decorators: Decorator[] | null; + /** Array of member declarations. */ declarations: VariableDeclaration[]; serialize(sb: string[]): void { @@ -1712,10 +1922,14 @@ export class VariableStatement extends Statement { } } +/** Represents a `while` statement. */ export class WhileStatement extends Statement { kind = NodeKind.WHILE; + + /** Condition expression. */ condition: Expression; + /** Statement being looped over. */ statement: Statement; serialize(sb: string[]): void { @@ -1726,35 +1940,72 @@ export class WhileStatement extends Statement { } } -export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): bool { - if (modifiers) - for (let i: i32 = 0, k: i32 = (modifiers).length; i < k; ++i) - if ((modifiers)[i].modifierKind == kind) - return true; - return false; +/** Cached unused modifiers for reuse. */ +let reusableModifiers: Modifier[] | null = null; + +export function setReusableModifiers(modifiers: Modifier[]) { + reusableModifiers = modifiers; } -function getDecoratorByName(name: string, decorators: Decorator[] | null): Decorator | null { +/** Creates a new modifiers array. */ +export function createModifiers(): Modifier[] { + let ret: Modifier[]; + if (reusableModifiers != null) { + ret = reusableModifiers; + reusableModifiers = null; + } else + ret = new Array(1); + ret.length = 0; + return ret; +} + +/** Adds a modifier to a modifiers array. Creates and returns a new array if `null`. */ +export function addModifier(modifier: Modifier, modifiers: Modifier[] | null): Modifier[] { + if (modifiers == null) + modifiers = createModifiers(); + modifiers.push(modifier); + return modifiers; +} + +/** Gets a specific modifier from the specified array of modifiers. */ +export function getModifier(kind: ModifierKind, modifiers: Modifier[] | null): Modifier | null { + if (modifiers) + for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) + if (modifiers[i].modifierKind == kind) + return modifiers[i]; + return null; +} + +/** Tests whether a specific modifier exists in the specified array of modifiers. */ +export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): bool { + return getModifier(kind, modifiers) != null; +} + +/** Gets a specific decorator within the specified decorators, if present. */ +export function getDecorator(name: string, decorators: Decorator[] | null): Decorator | null { if (decorators) for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) { const decorator: Decorator = decorators[i]; - const expression: Expression = decorator.expression; + const expression: Expression = decorator.name; if (expression.kind == NodeKind.IDENTIFIER && (expression).name == name) return decorator; } return null; } +/** Tests if a specific decorator is present within the specified decorators. */ export function hasDecorator(name: string, decorators: Decorator[] | null): bool { - return getDecoratorByName(name, decorators) != null; + return getDecorator(name, decorators) != null; } -export function serialize(node: Node, indent: i32 = 0): string { +/** Serializes the specified node to its TypeScript representation. */ +export function serialize(node: Node): string { const sb: string[] = new Array(); // shared builder could grow too much node.serialize(sb); return sb.join(""); } +/** Mangles a path to an internal path. */ export function mangleInternalPath(path: string): string { // TODO: not necessary with current config /* if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH) @@ -1764,22 +2015,9 @@ export function mangleInternalPath(path: string): string { return path; } +/** Mangles a declaration's name to an internal name. */ export function mangleInternalName(declaration: DeclarationStatement): string { - let name: string = declaration.identifier.name; - let modifiers: Modifier[] | null; - if (declaration.kind == NodeKind.METHOD && (modifiers = declaration.modifiers)) { - for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) { - const modifier: Modifier = modifiers[i]; - if (modifier.modifierKind == ModifierKind.GET) { - name = GETTER_PREFIX + name; - break; - } - else if (modifier.modifierKind == ModifierKind.SET) { - name = SETTER_PREFIX + name; - break; - } - } - } + let name: string = declaration.name.name; let parent: Node | null = declaration.parent; if (!parent) return name; @@ -1793,10 +2031,11 @@ export function mangleInternalName(declaration: DeclarationStatement): string { return declaration.range.source.internalPath + PATH_DELIMITER + name; } +/** Tests if the specified builder ends with the specified char code. */ function builderEndsWith(sb: string[], code: CharCode): bool { if (sb.length) { const last: string = sb[sb.length - 1]; - return last.length ? last.charCodeAt(last.length - 1) == code : false; + return select(last.charCodeAt(last.length - 1) == code, false, last.length > 0); } return false; } diff --git a/src/builtins.ts b/src/builtins.ts index 1989adee..03c95ec8 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -107,7 +107,7 @@ export function initialize(program: Program): void { } } -/** Adds a built-in global to the specified program. */ +/** Adds a built-in constant to the specified program. */ function addConstant(program: Program, name: string, type: Type): Global { const global: Global = new Global(program, name, null, null); global.isBuiltIn = true; diff --git a/src/compiler.ts b/src/compiler.ts index fd843e60..fb629581 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -58,6 +58,7 @@ import { ForStatement, IfStatement, ImportStatement, + InterfaceDeclaration, MethodDeclaration, ModifierKind, NamespaceDeclaration, @@ -93,8 +94,7 @@ import { UnaryPrefixExpression, // utility - hasModifier, - InterfaceDeclaration + hasModifier } from "./ast"; import { @@ -314,7 +314,7 @@ export class Compiler extends DiagnosticEmitter { return null; if (isModuleExport(element, declaration)) { if ((element).hasConstantValue) - this.module.addGlobalExport(element.internalName, declaration.identifier.name); + this.module.addGlobalExport(element.internalName, declaration.name.name); else this.warning(DiagnosticCode.Cannot_export_a_mutable_global, declaration.range); } @@ -334,7 +334,7 @@ export class Compiler extends DiagnosticEmitter { if (!declaration) throw new Error("unexpected missing declaration"); if (!declaration.type) { // TODO: infer type - this.error(DiagnosticCode.Type_expected, declaration.identifier.range); + this.error(DiagnosticCode.Type_expected, declaration.name.range); return false; } type = this.program.resolveType(declaration.type); // reports @@ -489,7 +489,7 @@ export class Compiler extends DiagnosticEmitter { if (!instance) return; if (isModuleExport(instance, declaration)) - this.module.addFunctionExport(instance.internalName, declaration.identifier.name); + this.module.addFunctionExport(instance.internalName, declaration.name.name); } compileFunctionUsingTypeArguments(prototype: FunctionPrototype, typeArguments: TypeNode[], contextualTypeArguments: Map | null = null, alternativeReportNode: Node | null = null): Function | null { @@ -509,12 +509,12 @@ export class Compiler extends DiagnosticEmitter { if (instance.isDeclared) { if (declaration.statements) { - this.error(DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, declaration.identifier.range); + this.error(DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, declaration.name.range); return false; } } else { if (!declaration.statements) { - this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, declaration.identifier.range); + this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, declaration.name.range); return false; } } @@ -546,7 +546,7 @@ export class Compiler extends DiagnosticEmitter { // create the function const internalName: string = instance.internalName; if (instance.isDeclared) { // TODO: use parent namespace as externalModuleName, if applicable - this.module.addFunctionImport(internalName, "env", declaration.identifier.name, typeRef); + this.module.addFunctionImport(internalName, "env", declaration.name.name, typeRef); } else { this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, stmts, NativeType.None)); } @@ -871,14 +871,14 @@ export class Compiler extends DiagnosticEmitter { compileIfStatement(statement: IfStatement): ExpressionRef { const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32); - const ifTrue: ExpressionRef = this.compileStatement(statement.statement); - const ifFalse: ExpressionRef = statement.elseStatement ? this.compileStatement(statement.elseStatement) : 0; + const ifTrue: ExpressionRef = this.compileStatement(statement.ifTrue); + const ifFalse: ExpressionRef = statement.ifFalse ? this.compileStatement(statement.ifFalse) : 0; return this.module.createIf(condition, ifTrue, ifFalse); } compileReturnStatement(statement: ReturnStatement): ExpressionRef { if (this.currentFunction) { - const expression: ExpressionRef = statement.expression ? this.compileExpression(statement.expression, this.currentFunction.returnType) : 0; + const expression: ExpressionRef = statement.value ? this.compileExpression(statement.value, this.currentFunction.returnType) : 0; return this.module.createReturn(expression); } return this.module.createUnreachable(); @@ -895,7 +895,7 @@ export class Compiler extends DiagnosticEmitter { // prepend initializer to inner block const breaks: ExpressionRef[] = new Array(1 + k); - breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.expression, Type.i32)); // initializer + breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.condition, Type.i32)); // initializer // make one br_if per (possibly dynamic) labeled case (binaryen optimizes to br_table where possible) let breakIndex: i32 = 1; @@ -966,18 +966,18 @@ export class Compiler extends DiagnosticEmitter { for (let i: i32 = 0, k = declarations.length; i < k; ++i) { const declaration: VariableDeclaration = declarations[i]; if (declaration.type) { - const name: string = declaration.identifier.name; + const name: string = declaration.name.name; const type: Type | null = this.program.resolveType(declaration.type, this.currentFunction.contextualTypeArguments, true); // reports if (type) { if (this.currentFunction.locals.has(name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name); // recoverable + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); // recoverable else this.currentFunction.addLocal(type, name); if (declaration.initializer) - initializers.push(this.compileAssignment(declaration.identifier, declaration.initializer, Type.void)); + initializers.push(this.compileAssignment(declaration.name, declaration.initializer, Type.void)); } } else { - this.error(DiagnosticCode.Type_expected, declaration.identifier.range); + this.error(DiagnosticCode.Type_expected, declaration.name.range); } } return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop(); @@ -1984,7 +1984,7 @@ export class Compiler extends DiagnosticEmitter { const operator: Token = expression.operator; // make a getter for the expression (also obtains the type) - const getValue: ExpressionRef = this.compileExpression(expression.expression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT); + const getValue: ExpressionRef = this.compileExpression(expression.operand, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT); // use a temp local for the intermediate value const tempLocal: Local = this.currentFunction.getTempLocal(this.currentType); @@ -2015,7 +2015,7 @@ export class Compiler extends DiagnosticEmitter { } // make a setter that sets the new value (temp value +/- 1) - const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.expression, + const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.operand, this.module.createBinary(op, this.module.createGetLocal(tempLocal.index, nativeType), nativeOne @@ -2034,7 +2034,7 @@ export class Compiler extends DiagnosticEmitter { } compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): ExpressionRef { - const operandExpression: Expression = expression.expression; + const operandExpression: Expression = expression.operand; let operand: ExpressionRef; let op: UnaryOp; diff --git a/src/parser.ts b/src/parser.ts index 4d1f06d2..a6f71f1b 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -64,21 +64,30 @@ import { VariableDeclaration, WhileStatement, - hasModifier + addModifier, + getModifier, + hasModifier, + setReusableModifiers } from "./ast"; +/** Parser interface. */ export class Parser extends DiagnosticEmitter { + /** Program being created. */ program: Program; + /** Log of source file names to be requested. */ backlog: string[] = new Array(); + /** Log of source file names already processed. */ seenlog: Set = new Set(); + /** Constructs a new parser. */ constructor() { super(); this.program = new Program(this.diagnostics); } + /** Parses a file and adds its definitions to the program. */ parseFile(text: string, path: string, isEntry: bool): void { const normalizedPath: string = normalizePath(path); for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i) @@ -99,7 +108,6 @@ export class Parser extends DiagnosticEmitter { statement.parent = source; source.statements.push(statement); } - reusableModifiers = null; } parseTopLevelStatement(tn: Tokenizer, isNamespaceMember: bool = false): Statement | null { @@ -129,6 +137,7 @@ export class Parser extends DiagnosticEmitter { tn.mark(); let statement: Statement | null = null; + let modifier: Modifier | null; switch (tn.next()) { case Token.CONST: @@ -175,12 +184,12 @@ export class Parser extends DiagnosticEmitter { break; case Token.IMPORT: - if (hasModifier(ModifierKind.EXPORT, modifiers)) { - statement = this.parseExportImport(tn, getModifier(ModifierKind.EXPORT, modifiers).range); + if (modifier = getModifier(ModifierKind.EXPORT, modifiers)) { + statement = this.parseExportImport(tn, modifier.range); } else statement = this.parseImport(tn); if (modifiers) - reusableModifiers = modifiers; + setReusableModifiers(modifiers); break; case Token.TYPE: @@ -192,9 +201,9 @@ export class Parser extends DiagnosticEmitter { statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again? } else { if (modifiers) { - if (hasModifier(ModifierKind.DECLARE, modifiers)) - this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.DECLARE, modifiers).range, "declare"); // recoverable - reusableModifiers = modifiers; + if (modifier = getModifier(ModifierKind.DECLARE, modifiers)) + this.error(DiagnosticCode._0_modifier_cannot_be_used_here, modifier.range, "declare"); // recoverable + setReusableModifiers(modifiers); } tn.reset(); if (!isNamespaceMember) @@ -210,6 +219,7 @@ export class Parser extends DiagnosticEmitter { return statement; } + /** Obtains the next file to parse. */ nextFile(): string | null { if (this.backlog.length) { const filename: string = this.backlog[0]; @@ -221,6 +231,7 @@ export class Parser extends DiagnosticEmitter { return null; } + /** Finishes parsing and returns the program. */ finish(): Program { if (this.backlog.length) throw new Error("backlog is not empty"); @@ -775,12 +786,13 @@ export class Parser extends DiagnosticEmitter { // field: (':' Type)? ('=' Expression)? ';'? } else { - if (hasModifier(ModifierKind.ABSTRACT, modifiers)) - this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.ABSTRACT, modifiers).range, "abstract"); // recoverable - if (hasModifier(ModifierKind.GET, modifiers)) - this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.GET, modifiers).range, "get"); // recoverable - if (hasModifier(ModifierKind.SET, modifiers)) - this.error(DiagnosticCode._0_modifier_cannot_be_used_here,getModifier(ModifierKind.SET, modifiers).range, "set"); // recoverable + let modifier: Modifier | null; + if (modifier = getModifier(ModifierKind.ABSTRACT, modifiers)) + this.error(DiagnosticCode._0_modifier_cannot_be_used_here, modifier.range, "abstract"); // recoverable + if (modifier = getModifier(ModifierKind.GET, modifiers)) + this.error(DiagnosticCode._0_modifier_cannot_be_used_here, modifier.range, "get"); // recoverable + if (modifier = getModifier(ModifierKind.SET, modifiers)) + this.error(DiagnosticCode._0_modifier_cannot_be_used_here, modifier.range, "set"); // recoverable let type: TypeNode | null = null; if (tn.skip(Token.COLON)) { type = this.parseType(tn); @@ -1323,7 +1335,7 @@ export class Parser extends DiagnosticEmitter { // expressions // see: http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm#climbing - parseExpressionPrefix(tn: Tokenizer): Expression | null { + parseExpressionStart(tn: Tokenizer): Expression | null { const token: Token = tn.next(); const startPos: i32 = tn.tokenPos; let expr: Expression | null = null; @@ -1335,7 +1347,7 @@ export class Parser extends DiagnosticEmitter { if (token == Token.FALSE) return Node.createFalse(tn.range()); - let p: Precedence = determinePrecedencePrefix(token); + let p: Precedence = determinePrecedenceStart(token); if (p != Precedence.INVALID) { let operand: Expression | null @@ -1487,7 +1499,7 @@ export class Parser extends DiagnosticEmitter { } parseExpression(tn: Tokenizer, precedence: Precedence = 0): Expression | null { - let expr: Expression | null = this.parseExpressionPrefix(tn); + let expr: Expression | null = this.parseExpressionStart(tn); if (!expr) return null; @@ -1581,7 +1593,7 @@ export class Parser extends DiagnosticEmitter { } } -enum Precedence { +const enum Precedence { COMMA, SPREAD, YIELD, @@ -1606,7 +1618,8 @@ enum Precedence { INVALID = -1 } -function determinePrecedencePrefix(kind: Token): i32 { +/** Determines the precedence of a starting token. */ +function determinePrecedenceStart(kind: Token): i32 { switch (kind) { case Token.DOT_DOT_DOT: @@ -1634,7 +1647,8 @@ function determinePrecedencePrefix(kind: Token): i32 { } } -function determinePrecedence(kind: Token): i32 { // non-prefix +/** Determines the precende of a non-starting token. */ +function determinePrecedence(kind: Token): i32 { switch (kind) { case Token.COMMA: @@ -1718,7 +1732,8 @@ function determinePrecedence(kind: Token): i32 { // non-prefix } } -function isRightAssociative(kind: Token): bool { // non-prefix +/** Determines whether a non-starting token is right associative. */ +function isRightAssociative(kind: Token): bool { switch (kind) { case Token.EQUALS: @@ -1742,30 +1757,3 @@ function isRightAssociative(kind: Token): bool { // non-prefix return false; } } - -let reusableModifiers: Modifier[] | null = null; - -function createModifiers(): Modifier[] { - let ret: Modifier[]; - if (reusableModifiers != null) { - ret = reusableModifiers; - reusableModifiers = null; - } else - ret = new Array(1); - ret.length = 0; - return ret; -} - -function addModifier(modifier: Modifier, modifiers: Modifier[] | null): Modifier[] { - if (modifiers == null) - modifiers = createModifiers(); - modifiers.push(modifier); - return modifiers; -} - -function getModifier(kind: ModifierKind, modifiers: Modifier[]): Modifier { - for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) - if (modifiers[i].modifierKind == kind) - return modifiers[i]; - throw new Error("no such modifier"); -} diff --git a/src/program.ts b/src/program.ts index 024f09f4..8f7d1984 100644 --- a/src/program.ts +++ b/src/program.ts @@ -216,31 +216,31 @@ export class Program extends DiagnosticEmitter { private initializeClass(declaration: ClassDeclaration, namespace: Element | null = null): void { const internalName: string = declaration.internalName; if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } - const prototype: ClassPrototype = new ClassPrototype(this, declaration.identifier.name, internalName, declaration); + const prototype: ClassPrototype = new ClassPrototype(this, declaration.name.name, internalName, declaration); this.elements.set(internalName, prototype); if (hasDecorator("global", declaration.decorators)) { - if (this.elements.has(declaration.identifier.name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (this.elements.has(declaration.name.name)) + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); else - this.elements.set(declaration.identifier.name, prototype); + this.elements.set(declaration.name.name, prototype); } if (namespace) { if (namespace.members) { - if (namespace.members.has(declaration.identifier.name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (namespace.members.has(declaration.name.name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else namespace.members = new Map(); - namespace.members.set(declaration.identifier.name, prototype); + namespace.members.set(declaration.name.name, prototype); } else if (prototype.isExported) { if (this.exports.has(internalName)) { - this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); return; } this.exports.set(internalName, prototype); @@ -265,18 +265,18 @@ export class Program extends DiagnosticEmitter { } private initializeField(declaration: FieldDeclaration, classPrototype: ClassPrototype): void { - const name: string = declaration.identifier.name; + const name: string = declaration.name.name; const internalName: string = declaration.internalName; // static fields become global variables if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) { if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } if (classPrototype.members) { if (classPrototype.members.has(name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } } else @@ -289,7 +289,7 @@ export class Program extends DiagnosticEmitter { } else { if (classPrototype.instanceMembers) { if (classPrototype.instanceMembers.has(name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } } else @@ -300,18 +300,18 @@ export class Program extends DiagnosticEmitter { } private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void { - let name: string = declaration.identifier.name; + let name: string = declaration.name.name; const internalName: string = declaration.internalName; // static methods become global functions if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) { if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } if (classPrototype.members) { if (classPrototype.members.has(name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } } else @@ -324,7 +324,7 @@ export class Program extends DiagnosticEmitter { } else { if (classPrototype.instanceMembers) { if (classPrototype.instanceMembers.has(name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName); return; } } else @@ -337,7 +337,7 @@ export class Program extends DiagnosticEmitter { private initializeEnum(declaration: EnumDeclaration, namespace: Element | null = null): void { const internalName: string = declaration.internalName; if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } const enm: Enum = new Enum(this, internalName, declaration); @@ -345,32 +345,32 @@ export class Program extends DiagnosticEmitter { if (namespace) { if (namespace.members) { - if (namespace.members.has(declaration.identifier.name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (namespace.members.has(declaration.name.name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else namespace.members = new Map(); - namespace.members.set(declaration.identifier.name, enm); + namespace.members.set(declaration.name.name, enm); } else if (enm.isExported) { if (this.exports.has(internalName)) { - this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); return; } this.exports.set(internalName, enm); } - const values: EnumValueDeclaration[] = declaration.members; + const values: EnumValueDeclaration[] = declaration.values; for (let i: i32 = 0, k: i32 = values.length; i < k; ++i) this.initializeEnumValue(values[i], enm); } private initializeEnumValue(declaration: EnumValueDeclaration, enm: Enum): void { - const name: string = declaration.identifier.name; + const name: string = declaration.name.name; const internalName: string = declaration.internalName; if (enm.members) { if (enm.members.has(name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else @@ -462,31 +462,31 @@ export class Program extends DiagnosticEmitter { private initializeFunction(declaration: FunctionDeclaration, namespace: Element | null = null): void { const internalName: string = declaration.internalName; if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } - const prototype: FunctionPrototype = new FunctionPrototype(this, declaration.identifier.name, internalName, declaration, null); + const prototype: FunctionPrototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null); this.elements.set(internalName, prototype); if (hasDecorator("global", declaration.decorators)) { - if (this.elements.has(declaration.identifier.name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (this.elements.has(declaration.name.name)) + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); else - this.elements.set(declaration.identifier.name, prototype); + this.elements.set(declaration.name.name, prototype); } if (namespace) { if (namespace.members) { - if (namespace.members.has(declaration.identifier.name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (namespace.members.has(declaration.name.name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else namespace.members = new Map(); - namespace.members.set(declaration.identifier.name, prototype); + namespace.members.set(declaration.name.name, prototype); } else if (prototype.isExported) { if (this.exports.has(internalName)) { - this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); return; } this.exports.set(internalName, prototype); @@ -504,7 +504,7 @@ export class Program extends DiagnosticEmitter { private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map, queuedImports: QueuedImport[]): void { const internalName: string = declaration.internalName; if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } @@ -548,10 +548,10 @@ export class Program extends DiagnosticEmitter { private initializeInterface(declaration: InterfaceDeclaration, namespace: Element | null = null): void { const internalName: string = declaration.internalName; - const prototype: InterfacePrototype = new InterfacePrototype(this, declaration.identifier.name, internalName, declaration); + const prototype: InterfacePrototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration); if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } this.elements.set(internalName, prototype); @@ -559,7 +559,7 @@ export class Program extends DiagnosticEmitter { if (namespace) { if (namespace.members) { if (namespace.members.has(prototype.internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else @@ -567,7 +567,7 @@ export class Program extends DiagnosticEmitter { namespace.members.set(prototype.internalName, prototype); } else if (prototype.isExported) { if (this.exports.has(internalName)) { - this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); return; } this.exports.set(internalName, prototype); @@ -602,16 +602,16 @@ export class Program extends DiagnosticEmitter { if (parentNamespace) { if (parentNamespace.members) { - if (parentNamespace.members.has(declaration.identifier.name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (parentNamespace.members.has(declaration.name.name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); return; } } else parentNamespace.members = new Map(); - parentNamespace.members.set(declaration.identifier.name, namespace); + parentNamespace.members.set(declaration.name.name, namespace); } else if (namespace.isExported) { if (this.exports.has(internalName)) { - this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); return; } this.exports.set(internalName, namespace); @@ -657,7 +657,7 @@ export class Program extends DiagnosticEmitter { const declaration: VariableDeclaration = declarations[i]; const internalName: string = declaration.internalName; if (this.elements.has(internalName)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); continue; } @@ -665,24 +665,24 @@ export class Program extends DiagnosticEmitter { this.elements.set(internalName, global); if (hasDecorator("global", declaration.decorators)) { - if (this.elements.has(declaration.identifier.name)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (this.elements.has(declaration.name.name)) + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); else - this.elements.set(declaration.identifier.name, global); + this.elements.set(declaration.name.name, global); } if (namespace) { if (namespace.members) { - if (namespace.members.has(declaration.identifier.name)) { - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + if (namespace.members.has(declaration.name.name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); continue; } } else namespace.members = new Map(); - namespace.members.set(declaration.identifier.name, global); + namespace.members.set(declaration.name.name, global); } else if (global.isExported) { if (this.exports.has(internalName)) - this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); else this.exports.set(internalName, global); } @@ -817,7 +817,7 @@ function hasDecorator(name: string, decorators: Decorator[] | null): bool { if (decorators) for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) { const decorator: Decorator = decorators[i]; - const expression: Expression = decorator.expression; + const expression: Expression = decorator.name; const args: Expression[] = decorator.arguments; if (expression.kind == NodeKind.IDENTIFIER && args.length <= 1 && (expression).name == name) return true; @@ -1192,7 +1192,7 @@ export class FunctionPrototype extends Element { if (typeNode) { const type: Type | null = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports if (type) { - parameters[i] = new Parameter(declaration.parameters[i].identifier.name, type); + parameters[i] = new Parameter(declaration.parameters[i].name.name, type); parameterTypes[i] = type; } else return null; diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 697a1481..6d849de9 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -21,7 +21,7 @@ import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics"; import { Source } from "./ast"; -import { CharCode, isLineBreak } from "./util/charcode"; +import { CharCode, isLineBreak, isWhiteSpace, isIdentifierStart, isIdentifierPart, isDecimalDigit, isOctalDigit, isKeywordCharacter } from "./util/charcode"; import { I64 } from "./util/i64"; export enum Token { @@ -275,7 +275,7 @@ export function operatorTokenToString(token: Token): string { case Token.AMPERSAND_EQUALS: return "&="; case Token.BAR_EQUALS: return "|="; case Token.CARET_EQUALS: return "^="; - default: return "INVALID"; + default: assert(false); return ""; } } @@ -1088,82 +1088,3 @@ export class Tokenizer extends DiagnosticEmitter { : String.fromCharCode((((value32 - 65536) / 1024 | 0) + 0xD800) as i32, ((value32 - 65536) % 1024 + 0xDC00) as i32); } } - -function isWhiteSpace(c: i32): bool { - return c == CharCode.SPACE - || c == CharCode.TAB - || c == CharCode.VERTICALTAB - || c == CharCode.FORMFEED - || c == CharCode.NONBREAKINGSPACE - || c == CharCode.NEXTLINE - || c == CharCode.OGHAM - || c >= CharCode.ENQUAD && c <= CharCode.ZEROWIDTHSPACE - || c == CharCode.NARRINOBREAKSPACE - || c == CharCode.MATHEMATICALSPACE - || c == CharCode.IDEOGRAPHICSPACE - || c == CharCode.BYTEORDERMARK; -} - -function isDecimalDigit(c: i32): bool { - return c >= CharCode._0 && c <= CharCode._9; -} - -function isOctalDigit(c: i32): bool { - return c >= CharCode._0 && c <= CharCode._7; -} - -function isIdentifierStart(c: i32): bool { - return c >= CharCode.A && c <= CharCode.Z - || c >= CharCode.a && c <= CharCode.z - || c == CharCode.DOLLAR - || c == CharCode._ - || c > 0x7f && isUnicodeIdentifierStart(c); -} - -function isKeywordCharacter(c: i32): bool { - return c >= CharCode.a && c <= CharCode.z; -} - -function isIdentifierPart(c: i32): bool { - return c >= CharCode.A && c <= CharCode.Z - || c >= CharCode.a && c <= CharCode.z - || c >= CharCode._0 && c <= CharCode._9 - || c == CharCode.DOLLAR - || c == CharCode._ - || c > 0x7f && isUnicodeIdentifierPart(c); -} - -// storing as u16 to save memory -const unicodeIdentifierStart: u16[] = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; -const unicodeIdentifierPart: u16[] = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; - -function lookupInUnicodeMap(code: u16, map: u16[]): bool { - if (code < map[0]) - return false; - - let lo: i32 = 0; - let hi: i32 = map.length; - let mid: i32; - - while (lo + 1 < hi) { - mid = lo + (hi - lo) / 2; - mid -= mid % 2; - if (map[mid] <= code && code <= map[mid + 1]) - return true; - if (code < map[mid]) - hi = mid; - else - lo = mid + 2; - } - return false; -} - -function isUnicodeIdentifierStart(code: i32): bool { - if (code < 0 || code > 0xffff) return false; - return lookupInUnicodeMap(code as u16, unicodeIdentifierStart); -} - -function isUnicodeIdentifierPart(code: i32): bool { - if (code < 0 || code > 0xffff) return false; - return lookupInUnicodeMap(code as u16, unicodeIdentifierPart); -} diff --git a/src/types.ts b/src/types.ts index 01c927b3..94b2f034 100644 --- a/src/types.ts +++ b/src/types.ts @@ -91,11 +91,11 @@ export class Type { } /** Composes the respective nullable type of this type. */ - asNullable(): Type { + asNullable(): Type | null { assert(this.kind == TypeKind.USIZE); if (this.isNullable && !this.nullableType) (this.nullableType = new Type(this.kind, this.size)).isNullable = true; - return this.nullableType; + return this.nullableType; } /** Converts this type to its TypeScript representation. */ @@ -119,7 +119,7 @@ export class Type { case TypeKind.F32: return "f32"; case TypeKind.F64: return "f64"; case TypeKind.VOID: return "void"; - default: assert(false); return "INVALID"; + default: assert(false); return ""; } } diff --git a/src/util/charcode.ts b/src/util/charcode.ts index c542b581..0a0185ed 100644 --- a/src/util/charcode.ts +++ b/src/util/charcode.ts @@ -1,3 +1,4 @@ +/** An enum of named character codes. */ export const enum CharCode { NULL = 0, @@ -132,9 +133,104 @@ export const enum CharCode { VERTICALTAB = 0x0B } +/** Tests if the specified character code is some sort of line break. */ export function isLineBreak(c: CharCode): bool { - return c == CharCode.LINEFEED - || c == CharCode.CARRIAGERETURN - || c == CharCode.LINESEPARATOR - || c == CharCode.PARAGRAPHSEPARATOR; + switch (c) { + case CharCode.LINEFEED: + case CharCode.CARRIAGERETURN: + case CharCode.LINESEPARATOR: + case CharCode.PARAGRAPHSEPARATOR: + return true; + default: + return false; + } +} + +/** Tests if the specified character code is some sort of white space. */ +export function isWhiteSpace(c: i32): bool { + switch (c) { + case CharCode.SPACE: + case CharCode.TAB: + case CharCode.VERTICALTAB: + case CharCode.FORMFEED: + case CharCode.NONBREAKINGSPACE: + case CharCode.NEXTLINE: + case CharCode.OGHAM: + case CharCode.NARRINOBREAKSPACE: + case CharCode.MATHEMATICALSPACE: + case CharCode.IDEOGRAPHICSPACE: + case CharCode.BYTEORDERMARK: + return true; + default: + return c >= CharCode.ENQUAD && c <= CharCode.ZEROWIDTHSPACE; + } +} + +/** Tests if the specified character code is a decimal digit. */ +export function isDecimalDigit(c: i32): bool { + return c >= CharCode._0 && c <= CharCode._9; +} + +/** Tests if the specified character code is an octal digit. */ +export function isOctalDigit(c: i32): bool { + return c >= CharCode._0 && c <= CharCode._7; +} + +/** Tests if the specified character code is a valid first character of an identifier. */ +export function isIdentifierStart(c: i32): bool { + return c >= CharCode.A && c <= CharCode.Z + || c >= CharCode.a && c <= CharCode.z + || c == CharCode.DOLLAR + || c == CharCode._ + || c > 0x7f && isUnicodeIdentifierStart(c); +} + +/** Tests if the specified character code is a valid character within a keyword. */ +export function isKeywordCharacter(c: i32): bool { + return c >= CharCode.a && c <= CharCode.z; +} + +/** Tests if the specified character code is a valid character within an identifier. */ +export function isIdentifierPart(c: i32): bool { + return c >= CharCode.A && c <= CharCode.Z + || c >= CharCode.a && c <= CharCode.z + || c >= CharCode._0 && c <= CharCode._9 + || c == CharCode.DOLLAR + || c == CharCode._ + || c > 0x7f && isUnicodeIdentifierPart(c); +} + +// storing as u16 to save memory +const unicodeIdentifierStart: u16[] = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; +const unicodeIdentifierPart: u16[] = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; + +function lookupInUnicodeMap(code: u16, map: u16[]): bool { + if (code < map[0]) + return false; + + let lo: i32 = 0; + let hi: i32 = map.length; + let mid: i32; + + while (lo + 1 < hi) { + mid = lo + (hi - lo) / 2; + mid -= mid % 2; + if (map[mid] <= code && code <= map[mid + 1]) + return true; + if (code < map[mid]) + hi = mid; + else + lo = mid + 2; + } + return false; +} + +function isUnicodeIdentifierStart(code: i32): bool { + return code < 0 || code > 0xffff ? false + : lookupInUnicodeMap(code as u16, unicodeIdentifierStart); +} + +function isUnicodeIdentifierPart(code: i32): bool { + return code < 0 || code > 0xffff ? false + : lookupInUnicodeMap(code as u16, unicodeIdentifierPart); } diff --git a/src/util/i64.ts b/src/util/i64.ts index e74e4ddc..feb51530 100644 --- a/src/util/i64.ts +++ b/src/util/i64.ts @@ -9,6 +9,7 @@ */ // TODO: div/mod +// another option is to use a wasm-based polyfill, see examples/i64-polyfill. const I64_MIN_LO: i32 = 0; const I64_MIN_HI: i32 = 0x80000000 | 0; diff --git a/src/util/path.ts b/src/util/path.ts index a86b15f2..a19c472a 100644 --- a/src/util/path.ts +++ b/src/util/path.ts @@ -1,5 +1,6 @@ import { CharCode } from "./charcode"; +/** Normalizes the specified path, removing interior placeholders. Expects a posix-formatted string / not Windows compatible. */ export function normalize(path: string, trimExtension: bool = false, separator: CharCode = CharCode.SLASH): string { // expects a relative path @@ -77,10 +78,12 @@ export function normalize(path: string, trimExtension: bool = false, separator: return len > 0 ? path : "."; } +/** Resolves the specified path to a normalized path relative to the specified origin. */ export function resolve(normalizedPath: string, normalizedOrigin: string, separator: CharCode = CharCode.SLASH): string { return normalize(dirname(normalizedOrigin, separator) + String.fromCharCode(separator) + normalizedPath); } +/** Obtains the directory portion of a normalized path. */ export function dirname(normalizedPath: string, separator: CharCode = CharCode.SLASH): string { let pos: i32 = normalizedPath.length; while (--pos > 0) diff --git a/src/util/sb.ts b/src/util/sb.ts index be4d44dd..c55ed97a 100644 --- a/src/util/sb.ts +++ b/src/util/sb.ts @@ -1,2 +1,2 @@ -/** Shared string builder. */ +/** A shared string builder utilized to reduce overall array allocations. */ export const sb: string[] = []; diff --git a/tests/compiler/std/array.wast b/tests/compiler/std/array.wast index f3e04e4c..14e90d53 100644 --- a/tests/compiler/std/array.wast +++ b/tests/compiler/std/array.wast @@ -61,9 +61,9 @@ heap/HEAP_OFFSET heap/Heap Heap - heap/Heap.get_used - heap/Heap.get_free - heap/Heap.get_size + heap/Heap.used + heap/Heap.free + heap/Heap.size heap/Heap.allocate heap/Heap.dispose heap/Heap.copy diff --git a/tests/compiler/std/heap.wast b/tests/compiler/std/heap.wast index deca6c3c..2da6477e 100644 --- a/tests/compiler/std/heap.wast +++ b/tests/compiler/std/heap.wast @@ -183,9 +183,9 @@ heap/HEAP_OFFSET heap/Heap Heap - heap/Heap.get_used - heap/Heap.get_free - heap/Heap.get_size + heap/Heap.used + heap/Heap.free + heap/Heap.size heap/Heap.allocate heap/Heap.dispose heap/Heap.copy diff --git a/tests/compiler/ternary.ts b/tests/compiler/ternary.ts index 59fffd5d..b6ab6041 100644 --- a/tests/compiler/ternary.ts +++ b/tests/compiler/ternary.ts @@ -1,3 +1,7 @@ +0 ? unreachable() : 1; +1 ? 1 : unreachable(); +(0 ? unreachable() : 1) ? 1 : unreachable(); + let a: i32; a = 0 ? unreachable() : 1; diff --git a/tests/compiler/ternary.wast b/tests/compiler/ternary.wast index 723f3af0..2d016e23 100644 --- a/tests/compiler/ternary.wast +++ b/tests/compiler/ternary.wast @@ -6,6 +6,31 @@ (export "memory" (memory $0)) (start $start) (func $start (; 0 ;) (type $v) + (if + (i32.const 0) + (unreachable) + (drop + (i32.const 1) + ) + ) + (if + (i32.const 1) + (drop + (i32.const 1) + ) + (unreachable) + ) + (if + (if (result i32) + (i32.const 0) + (unreachable) + (i32.const 1) + ) + (drop + (i32.const 1) + ) + (unreachable) + ) (set_global $ternary/a (if (result i32) (i32.const 0)