AST cleanup; Definition generators scaffolding

This commit is contained in:
dcodeIO 2018-03-17 01:37:05 +01:00
parent eef923d124
commit faac3c31eb
50 changed files with 3272 additions and 2690 deletions

View File

@ -286,6 +286,9 @@ exports.main = function main(argv, options, callback) {
} }
} }
// Finish parsing
const program = assemblyscript.finishParsing(parser);
// Begin compilation // Begin compilation
const compilerOptions = assemblyscript.createOptions(); const compilerOptions = assemblyscript.createOptions();
assemblyscript.setTarget(compilerOptions, 0); assemblyscript.setTarget(compilerOptions, 0);
@ -301,7 +304,7 @@ exports.main = function main(argv, options, callback) {
(() => { (() => {
try { try {
stats.compileTime += measure(() => { stats.compileTime += measure(() => {
module = assemblyscript.compile(parser, compilerOptions); module = assemblyscript.compileProgram(program, compilerOptions);
}); });
} catch (e) { } catch (e) {
return callback(e); return callback(e);
@ -434,23 +437,23 @@ exports.main = function main(argv, options, callback) {
: path.basename(args.binaryFile) + ".map" : path.basename(args.binaryFile) + ".map"
: null; : null;
let binary; let wasm;
stats.emitCount++; stats.emitCount++;
stats.emitTime += measure(() => { stats.emitTime += measure(() => {
binary = module.toBinary(sourceMapURL) wasm = module.toBinary(sourceMapURL)
}); });
if (args.binaryFile.length) { if (args.binaryFile.length) {
writeFile(path.join(baseDir, args.binaryFile), binary.output); writeFile(path.join(baseDir, args.binaryFile), wasm.output);
} else { } else {
writeStdout(binary.output); writeStdout(wasm.output);
hasStdout = true; hasStdout = true;
} }
// Post-process source map // Post-process source map
if (binary.sourceMap != null) { if (wasm.sourceMap != null) {
if (args.binaryFile.length) { if (args.binaryFile.length) {
let sourceMap = JSON.parse(binary.sourceMap); let sourceMap = JSON.parse(wasm.sourceMap);
sourceMap.sourceRoot = exports.sourceMapRoot; sourceMap.sourceRoot = exports.sourceMapRoot;
sourceMap.sources.forEach((name, index) => { sourceMap.sources.forEach((name, index) => {
let text = null; let text = null;
@ -482,30 +485,6 @@ exports.main = function main(argv, options, callback) {
} }
} }
// Write text
if (
args.textFile != null || (
args.binaryFile == null &&
args.asmjsFile == null
)
) {
let text;
if (args.textFile && args.textFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
text = module.toText();
});
writeFile(path.join(baseDir, args.textFile), text);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
text = module.toText()
});
writeStdout(text);
hasStdout = true;
}
}
// Write asm.js // Write asm.js
if (args.asmjsFile != null) { if (args.asmjsFile != null) {
let asm; let asm;
@ -524,6 +503,62 @@ exports.main = function main(argv, options, callback) {
hasStdout = true; hasStdout = true;
} }
} }
// Write WebIDL
if (args.idlFile != null) {
let idl;
if (args.idlFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
idl = assemblyscript.buildIDL(program);
});
writeFile(path.join(baseDir, args.idlFile), idl);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
idl = assemblyscript.buildIDL(program);
});
writeStdout(idl);
hasStdout = true;
}
}
// Write TypeScript definition
if (args.tsdFile != null) {
let tsd;
if (args.tsdFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
tsd = assemblyscript.buildTSD(program);
});
writeFile(path.join(baseDir, args.tsdFile), tsd);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
tsd = assemblyscript.buildTSD(program);
});
writeStdout(tsd);
hasStdout = true;
}
}
// Write text (must be last)
if (args.textFile != null) {
let wat;
if (args.textFile && args.textFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
wat = module.toText();
});
writeFile(path.join(baseDir, args.textFile), wat);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
wat = module.toText()
});
writeStdout(wat);
}
}
} }
module.dispose(); module.dispose();

View File

@ -62,6 +62,16 @@
"type": "string", "type": "string",
"aliases": [ "a" ] "aliases": [ "a" ]
}, },
"idlFile": {
"desc": "Specifies the WebIDL output file (.idl).",
"type": "string",
"aliases": [ "i" ]
},
"tsdFile": {
"desc": "Specifies the TypeScript definition output file (.d.ts).",
"type": "string",
"aliases": [ "d" ]
},
"sourceMap": { "sourceMap": {
"desc": [ "desc": [
"Enables source map generation. Optionally takes the URL", "Enables source map generation. Optionally takes the URL",

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

2
dist/asc.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

19
lib/demangle/index.js Normal file
View File

@ -0,0 +1,19 @@
/**
* @file AssemblyScript demangler.
*/
module.exports = demangle;
/**
* Demangles module exports to a friendly object structure compatible with WebIDL and TypeScript
* definitions.
*/
function demangle(exports) {
var root = {};
for (let i in exports) {
if (exports.hasOwnProperty(i)) {
// TODO
}
}
return root;
}

View File

@ -47,7 +47,8 @@
"test:parser": "node tests/parser", "test:parser": "node tests/parser",
"test:compiler": "node tests/compiler", "test:compiler": "node tests/compiler",
"test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path", "test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path",
"test:pr": "npm run clean && npm test && npm run build && npm test && npm run clean" "test:pr": "npm run clean && npm test && npm run build && npm test && npm run clean",
"all": "npm run lint && npm run clean && npm test && npm run build && npm test"
}, },
"files": [ "files": [
"bin/", "bin/",

View File

@ -1,4 +1,5 @@
import { import {
CommonFlags,
PATH_DELIMITER, PATH_DELIMITER,
STATIC_DELIMITER, STATIC_DELIMITER,
INSTANCE_DELIMITER INSTANCE_DELIMITER
@ -37,7 +38,6 @@ export enum NodeKind {
ELEMENTACCESS, ELEMENTACCESS,
FALSE, FALSE,
FUNCTION, FUNCTION,
FUNCTIONARROW,
LITERAL, LITERAL,
NEW, NEW,
NULL, NULL,
@ -86,7 +86,6 @@ export enum NodeKind {
// special // special
DECORATOR, DECORATOR,
MODIFIER,
EXPORTMEMBER, EXPORTMEMBER,
SWITCHCASE SWITCHCASE
} }
@ -100,6 +99,15 @@ export abstract class Node {
range: Range; range: Range;
/** Parent node. */ /** Parent node. */
parent: Node | null = null; parent: Node | null = null;
/** Common flags indicating specific traits. */
flags: CommonFlags = CommonFlags.NONE;
/** Tests if this node has a specific flag or flags. */
is(flag: CommonFlags): bool { return (this.flags & flag) == flag; }
/** Tests if this node has one of the specified flags. */
isAny(flag: CommonFlags): bool { return (this.flags & flag) != 0; }
/** Sets a specific flag or flags. */
set(flag: CommonFlags): void { this.flags |= flag; }
// types // types
@ -212,13 +220,6 @@ export abstract class Node {
return stmt; return stmt;
} }
static createModifier(kind: ModifierKind, range: Range): ModifierNode {
var elem = new ModifierNode();
elem.range = range;
elem.modifierKind = kind;
return elem;
}
// expressions // expressions
static createIdentifierExpression( static createIdentifierExpression(
@ -341,12 +342,10 @@ export abstract class Node {
} }
static createFunctionExpression( static createFunctionExpression(
declaration: FunctionDeclaration, declaration: FunctionDeclaration
isArrow: bool = false
): FunctionExpression { ): FunctionExpression {
var expr = isArrow var expr = new FunctionExpression();
? new FunctionArrowExpression() expr.flags = declaration.flags & CommonFlags.ARROW;
: new FunctionExpression();
expr.range = declaration.range; expr.range = declaration.range;
expr.declaration = declaration; expr.declaration = declaration;
return expr; return expr;
@ -518,18 +517,18 @@ export abstract class Node {
extendsType: TypeNode | null, // can't be a function extendsType: TypeNode | null, // can't be a function
implementsTypes: TypeNode[], // can't be a function implementsTypes: TypeNode[], // can't be a function
members: DeclarationStatement[], members: DeclarationStatement[],
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): ClassDeclaration { ): ClassDeclaration {
var stmt = new ClassDeclaration(); var stmt = new ClassDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = identifier; identifier.parent = stmt; stmt.name = identifier; identifier.parent = stmt;
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt); stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt; stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.implementsTypes = implementsTypes; setParent(implementsTypes, stmt); stmt.implementsTypes = implementsTypes; setParent(implementsTypes, stmt);
stmt.members = members; setParent(members, stmt); stmt.members = members; setParent(members, stmt);
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -567,15 +566,15 @@ export abstract class Node {
static createEnumDeclaration( static createEnumDeclaration(
name: IdentifierExpression, name: IdentifierExpression,
members: EnumValueDeclaration[], members: EnumValueDeclaration[],
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): EnumDeclaration { ): EnumDeclaration {
var stmt = new EnumDeclaration(); var stmt = new EnumDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.values = members; setParent(members, stmt); stmt.values = members; setParent(members, stmt);
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -583,10 +582,12 @@ export abstract class Node {
static createEnumValueDeclaration( static createEnumValueDeclaration(
name: IdentifierExpression, name: IdentifierExpression,
value: Expression | null, value: Expression | null,
flags: CommonFlags,
range: Range range: Range
): EnumValueDeclaration { ): EnumValueDeclaration {
var stmt = new EnumValueDeclaration(); var stmt = new EnumValueDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.value = value; if (value) value.parent = stmt; stmt.value = value; if (value) value.parent = stmt;
return stmt; return stmt;
@ -595,11 +596,12 @@ export abstract class Node {
static createExportStatement( static createExportStatement(
members: ExportMember[], members: ExportMember[],
path: StringLiteralExpression | null, path: StringLiteralExpression | null,
modifiers: ModifierNode[] | null, flags: CommonFlags,
range: Range range: Range
): ExportStatement { ): ExportStatement {
var stmt = new ExportStatement(); var stmt = new ExportStatement();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.members = members; setParent(members, stmt); stmt.members = members; setParent(members, stmt);
stmt.path = path; stmt.path = path;
if (path) { if (path) {
@ -617,7 +619,6 @@ export abstract class Node {
stmt.normalizedPath = null; stmt.normalizedPath = null;
stmt.internalPath = null; stmt.internalPath = null;
} }
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
return stmt; return stmt;
} }
@ -735,15 +736,15 @@ export abstract class Node {
name: IdentifierExpression, name: IdentifierExpression,
extendsType: TypeNode | null, // can't be a function extendsType: TypeNode | null, // can't be a function
members: DeclarationStatement[], members: DeclarationStatement[],
modifiers: ModifierNode[] | null, flags: CommonFlags,
range: Range range: Range
): InterfaceDeclaration { ): InterfaceDeclaration {
var stmt = new InterfaceDeclaration(); var stmt = new InterfaceDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt; stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.members = members; setParent(members, stmt); stmt.members = members; setParent(members, stmt);
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
return stmt; return stmt;
} }
@ -751,16 +752,16 @@ export abstract class Node {
name: IdentifierExpression, name: IdentifierExpression,
type: CommonTypeNode | null, type: CommonTypeNode | null,
initializer: Expression | null, initializer: Expression | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): FieldDeclaration { ): FieldDeclaration {
var stmt = new FieldDeclaration(); var stmt = new FieldDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.type = type; if (type) type.parent = stmt; stmt.type = type; if (type) type.parent = stmt;
stmt.initializer = initializer; if (initializer) initializer.parent = stmt; stmt.initializer = initializer; if (initializer) initializer.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -786,17 +787,17 @@ export abstract class Node {
typeParameters: TypeParameterNode[] | null, typeParameters: TypeParameterNode[] | null,
signature: SignatureNode, signature: SignatureNode,
body: Statement | null, body: Statement | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): FunctionDeclaration { ): FunctionDeclaration {
var stmt = new FunctionDeclaration(); var stmt = new FunctionDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt); stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.signature = signature; signature.parent = stmt; stmt.signature = signature; signature.parent = stmt;
stmt.body = body; if (body) body.parent = stmt; stmt.body = body; if (body) body.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -806,17 +807,17 @@ export abstract class Node {
typeParameters: TypeParameterNode[] | null, typeParameters: TypeParameterNode[] | null,
signature: SignatureNode, signature: SignatureNode,
body: Statement | null, body: Statement | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): MethodDeclaration { ): MethodDeclaration {
var stmt = new MethodDeclaration(); var stmt = new MethodDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt); stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.signature = signature; signature.parent = stmt; stmt.signature = signature; signature.parent = stmt;
stmt.body = body; if (body) body.parent = stmt; stmt.body = body; if (body) body.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -824,15 +825,15 @@ export abstract class Node {
static createNamespaceDeclaration( static createNamespaceDeclaration(
name: IdentifierExpression, name: IdentifierExpression,
members: Statement[], members: Statement[],
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): NamespaceDeclaration { ): NamespaceDeclaration {
var stmt = new NamespaceDeclaration(); var stmt = new NamespaceDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.members = members; setParent(members, stmt); stmt.members = members; setParent(members, stmt);
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -904,30 +905,30 @@ export abstract class Node {
name: IdentifierExpression, name: IdentifierExpression,
typeParameters: TypeParameterNode[] | null, typeParameters: TypeParameterNode[] | null,
alias: CommonTypeNode, alias: CommonTypeNode,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): TypeDeclaration { ): TypeDeclaration {
var stmt = new TypeDeclaration(); var stmt = new TypeDeclaration();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt; stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt); stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.type = alias; alias.parent = stmt; stmt.type = alias; alias.parent = stmt;
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
static createVariableStatement( static createVariableStatement(
declarations: VariableDeclaration[], declarations: VariableDeclaration[],
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): VariableStatement { ): VariableStatement {
var stmt = new VariableStatement(); var stmt = new VariableStatement();
stmt.range = range; stmt.range = range;
stmt.flags = flags;
stmt.declarations = declarations; setParent(declarations, stmt); stmt.declarations = declarations; setParent(declarations, stmt);
stmt.modifiers = modifiers; if (modifiers) setParent(modifiers, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt); stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt; return stmt;
} }
@ -936,16 +937,16 @@ export abstract class Node {
name: IdentifierExpression, name: IdentifierExpression,
type: CommonTypeNode | null, type: CommonTypeNode | null,
initializer: Expression | null, initializer: Expression | null,
modifiers: ModifierNode[] | null,
decorators: DecoratorNode[] | null, decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range range: Range
): VariableDeclaration { ): VariableDeclaration {
var elem = new VariableDeclaration(); var elem = new VariableDeclaration();
elem.range = range; elem.range = range;
elem.flags = flags;
elem.name = name; name.parent = elem; elem.name = name; name.parent = elem;
elem.type = type; if (type) type.parent = elem; elem.type = type; if (type) type.parent = elem;
elem.initializer = initializer; if (initializer) initializer.parent = elem; elem.initializer = initializer; if (initializer) initializer.parent = elem;
elem.modifiers = modifiers; // inherited from parent VariableStatement
elem.decorators = decorators; // inherited elem.decorators = decorators; // inherited
return elem; return elem;
} }
@ -1061,32 +1062,6 @@ export class DecoratorNode extends Node {
arguments: Expression[] | null; arguments: Expression[] | null;
} }
/** Indicates the specific kind of a modifier. */
export enum ModifierKind {
ASYNC,
CONST,
LET,
DECLARE,
EXPORT,
IMPORT,
STATIC,
ABSTRACT,
PUBLIC,
PRIVATE,
PROTECTED,
READONLY,
GET,
SET,
}
/** Represents a single modifier. */
export class ModifierNode extends Node {
kind = NodeKind.MODIFIER;
/** Specific modifier kind. */
modifierKind: ModifierKind;
}
// expressions // expressions
/** Base class of all expression nodes. */ /** Base class of all expression nodes. */
@ -1208,11 +1183,6 @@ export class FunctionExpression extends Expression {
declaration: FunctionDeclaration; declaration: FunctionDeclaration;
} }
/** Represents an arrow function expression. */
export class FunctionArrowExpression extends FunctionExpression {
kind = NodeKind.FUNCTIONARROW;
}
/** Represents an integer literal expression. */ /** Represents an integer literal expression. */
export class IntegerLiteralExpression extends LiteralExpression { export class IntegerLiteralExpression extends LiteralExpression {
literalKind = LiteralKind.INTEGER; literalKind = LiteralKind.INTEGER;
@ -1380,8 +1350,6 @@ export abstract class DeclarationStatement extends Statement {
/** Simple name being declared. */ /** Simple name being declared. */
name: IdentifierExpression; name: IdentifierExpression;
/** Array of modifiers. */
modifiers: ModifierNode[] | null;
/** Array of decorators. */ /** Array of decorators. */
decorators: DecoratorNode[] | null = null; decorators: DecoratorNode[] | null = null;
@ -1423,21 +1391,12 @@ export abstract class DeclarationStatement extends Statement {
return false; return false;
} }
if (parent.kind == NodeKind.NAMESPACEDECLARATION) { if (parent.kind == NodeKind.NAMESPACEDECLARATION) {
return ( return this.is(CommonFlags.EXPORT) && (<NamespaceDeclaration>parent).isTopLevelExport;
hasModifier(ModifierKind.EXPORT, this.modifiers) &&
(<NamespaceDeclaration>parent).isTopLevelExport
);
} }
if (parent.kind == NodeKind.CLASSDECLARATION) { if (parent.kind == NodeKind.CLASSDECLARATION) {
return ( return this.is(CommonFlags.STATIC) && (<ClassDeclaration>parent).isTopLevelExport;
hasModifier(ModifierKind.STATIC, this.modifiers) &&
(<ClassDeclaration>parent).isTopLevelExport
);
} }
return ( return parent.kind == NodeKind.SOURCE && this.is(CommonFlags.EXPORT);
parent.kind == NodeKind.SOURCE &&
hasModifier(ModifierKind.EXPORT, this.modifiers)
);
} }
/** Tests if this declaration needs an explicit export. */ /** Tests if this declaration needs an explicit export. */
@ -1531,7 +1490,6 @@ export class EnumDeclaration extends DeclarationStatement {
/** Represents a value of an `enum` declaration. */ /** Represents a value of an `enum` declaration. */
export class EnumValueDeclaration extends DeclarationStatement { export class EnumValueDeclaration extends DeclarationStatement {
kind = NodeKind.ENUMVALUEDECLARATION; kind = NodeKind.ENUMVALUEDECLARATION;
modifiers = null;
// name is inherited // name is inherited
/** Value expression. */ /** Value expression. */
@ -1562,8 +1520,6 @@ export class ExportMember extends Node {
export class ExportStatement extends Statement { export class ExportStatement extends Statement {
kind = NodeKind.EXPORT; kind = NodeKind.EXPORT;
/** Array of modifiers. */
modifiers: ModifierNode[] | null;
/** Array of members. */ /** Array of members. */
members: ExportMember[]; members: ExportMember[];
/** Path being exported from, if applicable. */ /** Path being exported from, if applicable. */
@ -1636,7 +1592,6 @@ export class IfStatement extends Statement {
/** Represents an `import` declaration part of an {@link ImportStatement}. */ /** Represents an `import` declaration part of an {@link ImportStatement}. */
export class ImportDeclaration extends DeclarationStatement { export class ImportDeclaration extends DeclarationStatement {
kind = NodeKind.IMPORTDECLARATION; kind = NodeKind.IMPORTDECLARATION;
modifiers = null;
/** Identifier being imported. */ /** Identifier being imported. */
externalName: IdentifierExpression; externalName: IdentifierExpression;
@ -1739,17 +1694,12 @@ export class TypeDeclaration extends DeclarationStatement {
/** Represents a variable declaration part of a {@link VariableStatement}. */ /** Represents a variable declaration part of a {@link VariableStatement}. */
export class VariableDeclaration extends VariableLikeDeclarationStatement { export class VariableDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.VARIABLEDECLARATION; kind = NodeKind.VARIABLEDECLARATION;
/** Array of modifiers. */
modifiers: ModifierNode[] | null;
} }
/** Represents a variable statement wrapping {@link VariableDeclaration}s. */ /** Represents a variable statement wrapping {@link VariableDeclaration}s. */
export class VariableStatement extends Statement { export class VariableStatement extends Statement {
kind = NodeKind.VARIABLE; kind = NodeKind.VARIABLE;
/** Array of modifiers. */
modifiers: ModifierNode[] | null;
/** Array of decorators. */ /** Array of decorators. */
decorators: DecoratorNode[] | null; decorators: DecoratorNode[] | null;
/** Array of member declarations. */ /** Array of member declarations. */
@ -1774,52 +1724,6 @@ export class WhileStatement extends Statement {
statement: Statement; statement: Statement;
} }
/** Cached unused modifiers for reuse. */
var reusableModifiers: ModifierNode[] | null = null;
export function setReusableModifiers(modifiers: ModifierNode[]): void {
reusableModifiers = modifiers;
}
/** Creates a new modifiers array. */
export function createModifiers(): ModifierNode[] {
var ret: ModifierNode[];
if (reusableModifiers != null) {
ret = reusableModifiers;
reusableModifiers = null;
} else {
ret = [];
}
ret.length = 0;
return ret;
}
// Utility
/** Adds a modifier to a set of modifiers. Creates a new set if `null`. */
export function addModifier(modifier: ModifierNode, modifiers: ModifierNode[] | null): ModifierNode[] {
if (modifiers == null) modifiers = createModifiers();
modifiers.push(modifier);
return modifiers;
}
/** Gets a specific modifier from the specified set of modifiers. */
export function getModifier(kind: ModifierKind, modifiers: ModifierNode[] | null): ModifierNode | null {
if (modifiers) {
for (let i = 0, k = modifiers.length; i < k; ++i) {
if (modifiers[i].modifierKind == kind) {
return modifiers[i];
}
}
}
return null;
}
/** Tests whether a modifier exists in the specified set of modifiers. */
export function hasModifier(kind: ModifierKind, modifiers: ModifierNode[] | null): bool {
return getModifier(kind, modifiers) != null;
}
/** Gets the first decorator by name within at set of decorators, if present. */ /** Gets the first decorator by name within at set of decorators, if present. */
export function getFirstDecorator(name: string, decorators: DecoratorNode[] | null): DecoratorNode | null { export function getFirstDecorator(name: string, decorators: DecoratorNode[] | null): DecoratorNode | null {
if (decorators) { if (decorators) {
@ -1852,7 +1756,7 @@ export function mangleInternalName(declaration: DeclarationStatement, asGlobal:
} }
if (parent.kind == NodeKind.CLASSDECLARATION) { if (parent.kind == NodeKind.CLASSDECLARATION) {
return mangleInternalName(<ClassDeclaration>parent, asGlobal) + ( return mangleInternalName(<ClassDeclaration>parent, asGlobal) + (
hasModifier(ModifierKind.STATIC, declaration.modifiers) declaration.is(CommonFlags.STATIC)
? STATIC_DELIMITER ? STATIC_DELIMITER
: INSTANCE_DELIMITER : INSTANCE_DELIMITER
) + name; ) + name;

View File

@ -2338,7 +2338,7 @@ export function compileAllocate(
var module = compiler.module; var module = compiler.module;
var options = compiler.options; var options = compiler.options;
var prototype = program.elements.get(options.allocateImpl); var prototype = program.elementsLookup.get(options.allocateImpl);
if (!prototype) { if (!prototype) {
program.error( program.error(
DiagnosticCode.Cannot_find_name_0, DiagnosticCode.Cannot_find_name_0,
@ -2377,10 +2377,10 @@ export function compileAbort(
var program = compiler.program; var program = compiler.program;
var module = compiler.module; var module = compiler.module;
var stringType = program.types.get("string"); // might be intended var stringType = program.typesLookup.get("string"); // might be intended
if (!stringType) return module.createUnreachable(); if (!stringType) return module.createUnreachable();
var abortPrototype = program.elements.get("abort"); // might be intended var abortPrototype = program.elementsLookup.get("abort"); // might be intended
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable(); if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports

View File

@ -39,7 +39,7 @@ import {
Property, Property,
VariableLikeElement, VariableLikeElement,
FlowFlags, FlowFlags,
ElementFlags, CommonFlags,
ConstantValueKind, ConstantValueKind,
PATH_DELIMITER, PATH_DELIMITER,
@ -47,7 +47,8 @@ import {
} from "./program"; } from "./program";
import { import {
Token Token,
operatorTokenToString
} from "./tokenizer"; } from "./tokenizer";
import { import {
@ -72,7 +73,6 @@ import {
IfStatement, IfStatement,
ImportStatement, ImportStatement,
InterfaceDeclaration, InterfaceDeclaration,
ModifierKind,
NamespaceDeclaration, NamespaceDeclaration,
ReturnStatement, ReturnStatement,
SwitchStatement, SwitchStatement,
@ -102,9 +102,7 @@ import {
ArrayLiteralExpression, ArrayLiteralExpression,
StringLiteralExpression, StringLiteralExpression,
UnaryPostfixExpression, UnaryPostfixExpression,
UnaryPrefixExpression, UnaryPrefixExpression
hasModifier
} from "./ast"; } from "./ast";
import { import {
@ -239,14 +237,13 @@ export class Compiler extends DiagnosticEmitter {
program.initialize(options); program.initialize(options);
// set up the start function wrapping top-level statements, of all files. // set up the start function wrapping top-level statements, of all files.
var startFunctionPrototype = assert(program.elements.get("start")); var startFunctionPrototype = assert(program.elementsLookup.get("start"));
assert(startFunctionPrototype.kind == ElementKind.FUNCTION_PROTOTYPE); assert(startFunctionPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
var startFunctionInstance = new Function( var startFunctionInstance = new Function(
<FunctionPrototype>startFunctionPrototype, <FunctionPrototype>startFunctionPrototype,
startFunctionPrototype.internalName, startFunctionPrototype.internalName,
new Signature([], Type.void) new Signature([], Type.void)
); );
startFunctionInstance.set(ElementFlags.START);
this.startFunction = startFunctionInstance; this.startFunction = startFunctionInstance;
this.currentFunction = startFunctionInstance; this.currentFunction = startFunctionInstance;
@ -383,10 +380,7 @@ export class Compiler extends DiagnosticEmitter {
switch (statement.kind) { switch (statement.kind) {
case NodeKind.CLASSDECLARATION: { case NodeKind.CLASSDECLARATION: {
if ( if (
( (noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) &&
noTreeShaking ||
(isEntry && hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>statement).modifiers))
) &&
!(<ClassDeclaration>statement).isGeneric !(<ClassDeclaration>statement).isGeneric
) { ) {
this.compileClassDeclaration(<ClassDeclaration>statement, []); this.compileClassDeclaration(<ClassDeclaration>statement, []);
@ -394,20 +388,14 @@ export class Compiler extends DiagnosticEmitter {
break; break;
} }
case NodeKind.ENUMDECLARATION: { case NodeKind.ENUMDECLARATION: {
if ( if (noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) {
noTreeShaking ||
(isEntry && hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>statement).modifiers))
) {
this.compileEnumDeclaration(<EnumDeclaration>statement); this.compileEnumDeclaration(<EnumDeclaration>statement);
} }
break; break;
} }
case NodeKind.FUNCTIONDECLARATION: { case NodeKind.FUNCTIONDECLARATION: {
if ( if (
( (noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) &&
noTreeShaking ||
(isEntry && hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>statement).modifiers))
) &&
!(<FunctionDeclaration>statement).isGeneric !(<FunctionDeclaration>statement).isGeneric
) { ) {
this.compileFunctionDeclaration(<FunctionDeclaration>statement, []); this.compileFunctionDeclaration(<FunctionDeclaration>statement, []);
@ -422,10 +410,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
} }
case NodeKind.NAMESPACEDECLARATION: { case NodeKind.NAMESPACEDECLARATION: {
if ( if (noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) {
noTreeShaking ||
(isEntry && hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>statement).modifiers))
) {
this.compileNamespaceDeclaration(<NamespaceDeclaration>statement); this.compileNamespaceDeclaration(<NamespaceDeclaration>statement);
} }
break; break;
@ -462,15 +447,15 @@ export class Compiler extends DiagnosticEmitter {
compileGlobalDeclaration(declaration: VariableDeclaration): Global | null { compileGlobalDeclaration(declaration: VariableDeclaration): Global | null {
// look up the initialized program element // look up the initialized program element
var element = assert(this.program.elements.get(declaration.fileLevelInternalName)); var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
assert(element.kind == ElementKind.GLOBAL); assert(element.kind == ElementKind.GLOBAL);
if (!this.compileGlobal(<Global>element)) return null; // reports if (!this.compileGlobal(<Global>element)) return null; // reports
return <Global>element; return <Global>element;
} }
compileGlobal(global: Global): bool { compileGlobal(global: Global): bool {
if (global.is(ElementFlags.COMPILED) || global.is(ElementFlags.BUILTIN)) return true; if (global.is(CommonFlags.COMPILED) || global.is(CommonFlags.BUILTIN)) return true;
global.set(ElementFlags.COMPILED); // ^ built-ins are compiled on use global.set(CommonFlags.COMPILED); // ^ built-ins are compiled on use
var module = this.module; var module = this.module;
var declaration = global.declaration; var declaration = global.declaration;
@ -520,10 +505,11 @@ export class Compiler extends DiagnosticEmitter {
var nativeType = global.type.toNativeType(); var nativeType = global.type.toNativeType();
// handle imports // handle imports
if (global.is(ElementFlags.DECLARED)) { if (global.is(CommonFlags.DECLARE)) {
// constant global // constant global
if (global.is(ElementFlags.CONSTANT)) { if (global.is(CommonFlags.CONST)) {
global.set(CommonFlags.MODULE_IMPORT);
module.addGlobalImport( module.addGlobalImport(
global.internalName, global.internalName,
global.namespace global.namespace
@ -532,7 +518,7 @@ export class Compiler extends DiagnosticEmitter {
global.simpleName, global.simpleName,
nativeType nativeType
); );
global.set(ElementFlags.COMPILED); global.set(CommonFlags.COMPILED);
return true; return true;
// importing mutable globals is not supported in the MVP // importing mutable globals is not supported in the MVP
@ -550,7 +536,7 @@ export class Compiler extends DiagnosticEmitter {
var initializeInStart = false; var initializeInStart = false;
// inlined constant can be compiled as-is // inlined constant can be compiled as-is
if (global.is(ElementFlags.INLINED)) { if (global.is(CommonFlags.INLINED)) {
initExpr = this.compileInlineConstant(global, global.type, true); initExpr = this.compileInlineConstant(global, global.type, true);
} else { } else {
@ -565,7 +551,7 @@ export class Compiler extends DiagnosticEmitter {
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
// if a constant global, check if the initializer becomes constant after precompute // if a constant global, check if the initializer becomes constant after precompute
if (global.is(ElementFlags.CONSTANT)) { if (global.is(CommonFlags.CONST)) {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
this.warning( this.warning(
@ -593,7 +579,7 @@ export class Compiler extends DiagnosticEmitter {
} else { // compile as-is } else { // compile as-is
if (global.is(ElementFlags.CONSTANT)) { if (global.is(CommonFlags.CONST)) {
let exprType = _BinaryenExpressionGetType(initExpr); let exprType = _BinaryenExpressionGetType(initExpr);
switch (exprType) { switch (exprType) {
case NativeType.I32: { case NativeType.I32: {
@ -630,7 +616,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
} }
} }
global.set(ElementFlags.INLINED); // inline the value from now on global.set(CommonFlags.INLINED); // inline the value from now on
if (declaration.isTopLevel) { // but keep the element if it might be re-exported if (declaration.isTopLevel) { // but keep the element if it might be re-exported
module.addGlobal(internalName, nativeType, false, initExpr); module.addGlobal(internalName, nativeType, false, initExpr);
} }
@ -639,7 +625,7 @@ export class Compiler extends DiagnosticEmitter {
} }
} else /* mutable */ { } else /* mutable */ {
module.addGlobal(internalName, nativeType, !global.is(ElementFlags.CONSTANT), initExpr); module.addGlobal(internalName, nativeType, !global.is(CommonFlags.CONST), initExpr);
} }
} }
return true; return true;
@ -648,15 +634,15 @@ export class Compiler extends DiagnosticEmitter {
// enums // enums
compileEnumDeclaration(declaration: EnumDeclaration): Enum | null { compileEnumDeclaration(declaration: EnumDeclaration): Enum | null {
var element = assert(this.program.elements.get(declaration.fileLevelInternalName)); var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
assert(element.kind == ElementKind.ENUM); assert(element.kind == ElementKind.ENUM);
if (!this.compileEnum(<Enum>element)) return null; if (!this.compileEnum(<Enum>element)) return null;
return <Enum>element; return <Enum>element;
} }
compileEnum(element: Enum): bool { compileEnum(element: Enum): bool {
if (element.is(ElementFlags.COMPILED)) return true; if (element.is(CommonFlags.COMPILED)) return true;
element.set(ElementFlags.COMPILED); element.set(CommonFlags.COMPILED);
var module = this.module; var module = this.module;
this.currentEnum = element; this.currentEnum = element;
@ -668,8 +654,8 @@ export class Compiler extends DiagnosticEmitter {
let initInStart = false; let initInStart = false;
let val = <EnumValue>member; let val = <EnumValue>member;
let valueDeclaration = val.declaration; let valueDeclaration = val.declaration;
val.set(ElementFlags.COMPILED); val.set(CommonFlags.COMPILED);
if (val.is(ElementFlags.INLINED)) { if (val.is(CommonFlags.INLINED)) {
if (element.declaration.isTopLevelExport) { if (element.declaration.isTopLevelExport) {
module.addGlobal( module.addGlobal(
val.internalName, val.internalName,
@ -685,7 +671,7 @@ export class Compiler extends DiagnosticEmitter {
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
if (element.is(ElementFlags.CONSTANT)) { if (element.is(CommonFlags.CONST)) {
this.warning( this.warning(
DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable,
valueDeclaration.range valueDeclaration.range
@ -696,7 +682,7 @@ export class Compiler extends DiagnosticEmitter {
} }
} else if (previousValue == null) { } else if (previousValue == null) {
initExpr = module.createI32(0); initExpr = module.createI32(0);
} else if (previousValue.is(ElementFlags.INLINED)) { } else if (previousValue.is(CommonFlags.INLINED)) {
initExpr = module.createI32(previousValue.constantValue + 1); initExpr = module.createI32(previousValue.constantValue + 1);
} else { } else {
// in TypeScript this errors with TS1061, but actually we can do: // in TypeScript this errors with TS1061, but actually we can do:
@ -704,7 +690,7 @@ export class Compiler extends DiagnosticEmitter {
module.createGetGlobal(previousValue.internalName, NativeType.I32), module.createGetGlobal(previousValue.internalName, NativeType.I32),
module.createI32(1) module.createI32(1)
); );
if (element.is(ElementFlags.CONSTANT)) { if (element.is(CommonFlags.CONST)) {
this.warning( this.warning(
DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable,
valueDeclaration.range valueDeclaration.range
@ -724,7 +710,7 @@ export class Compiler extends DiagnosticEmitter {
module.addGlobal(val.internalName, NativeType.I32, false, initExpr); module.addGlobal(val.internalName, NativeType.I32, false, initExpr);
if (_BinaryenExpressionGetType(initExpr) == NativeType.I32) { if (_BinaryenExpressionGetType(initExpr) == NativeType.I32) {
val.constantValue = _BinaryenConstGetValueI32(initExpr); val.constantValue = _BinaryenConstGetValueI32(initExpr);
val.set(ElementFlags.INLINED); val.set(CommonFlags.INLINED);
} else { } else {
assert(false); assert(false);
this.error( this.error(
@ -739,7 +725,7 @@ export class Compiler extends DiagnosticEmitter {
// export values if the enum is exported // export values if the enum is exported
if (element.declaration.range.source.isEntry && element.declaration.isTopLevelExport) { if (element.declaration.range.source.isEntry && element.declaration.isTopLevelExport) {
if (member.is(ElementFlags.INLINED)) { if (member.is(CommonFlags.INLINED)) {
module.addGlobalExport(member.internalName, member.internalName); module.addGlobalExport(member.internalName, member.internalName);
} else if (valueDeclaration) { } else if (valueDeclaration) {
this.warning( this.warning(
@ -762,7 +748,7 @@ export class Compiler extends DiagnosticEmitter {
typeArguments: TypeNode[], typeArguments: TypeNode[],
contextualTypeArguments: Map<string,Type> | null = null contextualTypeArguments: Map<string,Type> | null = null
): Function | null { ): Function | null {
var element = assert(this.program.elements.get(declaration.fileLevelInternalName)); var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE); assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
return this.compileFunctionUsingTypeArguments( // reports return this.compileFunctionUsingTypeArguments( // reports
<FunctionPrototype>element, <FunctionPrototype>element,
@ -816,22 +802,22 @@ export class Compiler extends DiagnosticEmitter {
/** Compiles a readily resolved function instance. */ /** Compiles a readily resolved function instance. */
compileFunction(instance: Function): bool { compileFunction(instance: Function): bool {
if (instance.is(ElementFlags.COMPILED)) return true; if (instance.is(CommonFlags.COMPILED)) return true;
assert(!instance.is(ElementFlags.BUILTIN) || instance.simpleName == "abort"); assert(!instance.is(CommonFlags.BUILTIN) || instance.simpleName == "abort");
instance.set(ElementFlags.COMPILED); instance.set(CommonFlags.COMPILED);
// check that modifiers are matching but still compile as-is // check that modifiers are matching but still compile as-is
var declaration = instance.prototype.declaration; var declaration = instance.prototype.declaration;
var body = declaration.body; var body = declaration.body;
if (body) { if (body) {
if (instance.is(ElementFlags.DECLARED)) { if (instance.is(CommonFlags.DECLARE)) {
this.error( this.error(
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
declaration.name.range declaration.name.range
); );
} }
} else { } else {
if (!instance.is(ElementFlags.DECLARED)) { if (!instance.is(CommonFlags.DECLARE)) {
this.error( this.error(
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
declaration.name.range declaration.name.range
@ -869,7 +855,7 @@ export class Compiler extends DiagnosticEmitter {
); );
} else { } else {
instance.set(ElementFlags.IMPORTED); instance.set(CommonFlags.MODULE_IMPORT);
// create the function import // create the function import
let namespace = instance.prototype.namespace; let namespace = instance.prototype.namespace;
@ -902,10 +888,8 @@ export class Compiler extends DiagnosticEmitter {
switch (member.kind) { switch (member.kind) {
case NodeKind.CLASSDECLARATION: { case NodeKind.CLASSDECLARATION: {
if ( if (
( (noTreeShaking || member.is(CommonFlags.EXPORT)) &&
noTreeShaking || !(<ClassDeclaration>member).isGeneric
hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>member).modifiers)
) && !(<ClassDeclaration>member).isGeneric
) { ) {
this.compileClassDeclaration(<ClassDeclaration>member, []); this.compileClassDeclaration(<ClassDeclaration>member, []);
} }
@ -913,30 +897,22 @@ export class Compiler extends DiagnosticEmitter {
} }
case NodeKind.INTERFACEDECLARATION: { case NodeKind.INTERFACEDECLARATION: {
if ( if (
( (noTreeShaking || member.is(CommonFlags.EXPORT)) &&
noTreeShaking || !(<InterfaceDeclaration>member).isGeneric
hasModifier(ModifierKind.EXPORT, (<InterfaceDeclaration>member).modifiers)
) && !(<InterfaceDeclaration>member).isGeneric
) { ) {
this.compileInterfaceDeclaration(<InterfaceDeclaration>member, []); this.compileInterfaceDeclaration(<InterfaceDeclaration>member, []);
} }
break; break;
} }
case NodeKind.ENUMDECLARATION: { case NodeKind.ENUMDECLARATION: {
if ( if (noTreeShaking || member.is(CommonFlags.EXPORT)) {
noTreeShaking ||
hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>member).modifiers)
) {
this.compileEnumDeclaration(<EnumDeclaration>member); this.compileEnumDeclaration(<EnumDeclaration>member);
} }
break; break;
} }
case NodeKind.FUNCTIONDECLARATION: { case NodeKind.FUNCTIONDECLARATION: {
if ( if (
( (noTreeShaking || member.is(CommonFlags.EXPORT)) &&
noTreeShaking ||
hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>member).modifiers)
) &&
!(<FunctionDeclaration>member).isGeneric !(<FunctionDeclaration>member).isGeneric
) { ) {
this.compileFunctionDeclaration(<FunctionDeclaration>member, []); this.compileFunctionDeclaration(<FunctionDeclaration>member, []);
@ -944,19 +920,13 @@ export class Compiler extends DiagnosticEmitter {
break; break;
} }
case NodeKind.NAMESPACEDECLARATION: { case NodeKind.NAMESPACEDECLARATION: {
if ( if (noTreeShaking || member.is(CommonFlags.EXPORT)) {
noTreeShaking ||
hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>member).modifiers)
) {
this.compileNamespaceDeclaration(<NamespaceDeclaration>member); this.compileNamespaceDeclaration(<NamespaceDeclaration>member);
} }
break; break;
} }
case NodeKind.VARIABLE: { case NodeKind.VARIABLE: {
if ( if (noTreeShaking || member.is(CommonFlags.EXPORT)) {
noTreeShaking ||
hasModifier(ModifierKind.EXPORT, (<VariableStatement>member).modifiers)
) {
let variableInit = this.compileVariableStatement(<VariableStatement>member, true); let variableInit = this.compileVariableStatement(<VariableStatement>member, true);
if (variableInit) this.startFunctionBody.push(variableInit); if (variableInit) this.startFunctionBody.push(variableInit);
} }
@ -984,8 +954,8 @@ export class Compiler extends DiagnosticEmitter {
if ( if (
( (
noTreeShaking || noTreeShaking ||
(<ClassPrototype>element).is(ElementFlags.EXPORTED) (<ClassPrototype>element).is(CommonFlags.EXPORT)
) && !(<ClassPrototype>element).is(ElementFlags.GENERIC) ) && !(<ClassPrototype>element).is(CommonFlags.GENERIC)
) { ) {
this.compileClassUsingTypeArguments(<ClassPrototype>element, []); this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
} }
@ -998,8 +968,8 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.FUNCTION_PROTOTYPE: { case ElementKind.FUNCTION_PROTOTYPE: {
if ( if (
( (
noTreeShaking || (<FunctionPrototype>element).is(ElementFlags.EXPORTED) noTreeShaking || (<FunctionPrototype>element).is(CommonFlags.EXPORT)
) && !(<FunctionPrototype>element).is(ElementFlags.GENERIC) ) && !(<FunctionPrototype>element).is(CommonFlags.GENERIC)
) { ) {
this.compileFunctionUsingTypeArguments( this.compileFunctionUsingTypeArguments(
<FunctionPrototype>element, <FunctionPrototype>element,
@ -1026,7 +996,7 @@ export class Compiler extends DiagnosticEmitter {
compileExportStatement(statement: ExportStatement): void { compileExportStatement(statement: ExportStatement): void {
var module = this.module; var module = this.module;
var exports = this.program.exports; var exports = this.program.fileLevelExports;
var members = statement.members; var members = statement.members;
for (let i = 0, k = members.length; i < k; ++i) { for (let i = 0, k = members.length; i < k; ++i) {
let member = members[i]; let member = members[i];
@ -1039,7 +1009,7 @@ export class Compiler extends DiagnosticEmitter {
if (!element) continue; // reported in Program#initialize if (!element) continue; // reported in Program#initialize
switch (element.kind) { switch (element.kind) {
case ElementKind.CLASS_PROTOTYPE: { case ElementKind.CLASS_PROTOTYPE: {
if (!(<ClassPrototype>element).is(ElementFlags.GENERIC)) { if (!(<ClassPrototype>element).is(CommonFlags.GENERIC)) {
this.compileClassUsingTypeArguments(<ClassPrototype>element, []); this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
} }
break; break;
@ -1050,7 +1020,7 @@ export class Compiler extends DiagnosticEmitter {
} }
case ElementKind.FUNCTION_PROTOTYPE: { case ElementKind.FUNCTION_PROTOTYPE: {
if ( if (
!(<FunctionPrototype>element).is(ElementFlags.GENERIC) && !(<FunctionPrototype>element).is(CommonFlags.GENERIC) &&
statement.range.source.isEntry statement.range.source.isEntry
) { ) {
let functionInstance = this.compileFunctionUsingTypeArguments( let functionInstance = this.compileFunctionUsingTypeArguments(
@ -1072,7 +1042,7 @@ export class Compiler extends DiagnosticEmitter {
if (this.compileGlobal(<Global>element) && statement.range.source.isEntry) { if (this.compileGlobal(<Global>element) && statement.range.source.isEntry) {
let globalDeclaration = (<Global>element).declaration; let globalDeclaration = (<Global>element).declaration;
if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) { if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) {
if ((<Global>element).is(ElementFlags.INLINED)) { if ((<Global>element).is(CommonFlags.INLINED)) {
module.addGlobalExport(element.internalName, member.externalName.text); module.addGlobalExport(element.internalName, member.externalName.text);
} else { } else {
this.warning( this.warning(
@ -1100,7 +1070,7 @@ export class Compiler extends DiagnosticEmitter {
contextualTypeArguments: Map<string,Type> | null = null, contextualTypeArguments: Map<string,Type> | null = null,
alternativeReportNode: Node | null = null alternativeReportNode: Node | null = null
): void { ): void {
var element = assert(this.program.elements.get(declaration.fileLevelInternalName)); var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
assert(element.kind == ElementKind.CLASS_PROTOTYPE); assert(element.kind == ElementKind.CLASS_PROTOTYPE);
this.compileClassUsingTypeArguments( this.compileClassUsingTypeArguments(
<ClassPrototype>element, <ClassPrototype>element,
@ -1126,8 +1096,8 @@ export class Compiler extends DiagnosticEmitter {
} }
compileClass(instance: Class): bool { compileClass(instance: Class): bool {
if (instance.is(ElementFlags.COMPILED)) return true; if (instance.is(CommonFlags.COMPILED)) return true;
instance.set(ElementFlags.COMPILED); instance.set(CommonFlags.COMPILED);
return true; return true;
} }
@ -1159,7 +1129,7 @@ export class Compiler extends DiagnosticEmitter {
/** Ensures that a table entry exists for the specified function and returns its index. */ /** Ensures that a table entry exists for the specified function and returns its index. */
ensureFunctionTableEntry(func: Function): i32 { ensureFunctionTableEntry(func: Function): i32 {
assert(func.is(ElementFlags.COMPILED)); assert(func.is(CommonFlags.COMPILED));
if (func.functionTableIndex >= 0) { if (func.functionTableIndex >= 0) {
return func.functionTableIndex; return func.functionTableIndex;
} }
@ -1671,7 +1641,7 @@ export class Compiler extends DiagnosticEmitter {
); );
continue; continue;
} }
if (hasModifier(ModifierKind.CONST, declaration.modifiers)) { if (declaration.is(CommonFlags.CONST)) {
if (init) { if (init) {
init = this.precomputeExpressionRef(init); init = this.precomputeExpressionRef(init);
if (_BinaryenExpressionGetId(init) == ExpressionId.Const) { if (_BinaryenExpressionGetId(init) == ExpressionId.Const) {
@ -1730,7 +1700,7 @@ export class Compiler extends DiagnosticEmitter {
); );
} }
} }
if (hasModifier(ModifierKind.LET, declaration.modifiers)) { // here: not top-level if (declaration.is(CommonFlags.LET)) { // here: not top-level
currentFunction.flow.addScopedLocal(name, type, declaration.name); // reports currentFunction.flow.addScopedLocal(name, type, declaration.name); // reports
} else { } else {
currentFunction.addLocal(type, name); // reports currentFunction.addLocal(type, name); // reports
@ -1809,7 +1779,7 @@ export class Compiler extends DiagnosticEmitter {
contextualType: Type, contextualType: Type,
retainType: bool retainType: bool
): ExpressionRef { ): ExpressionRef {
assert(element.is(ElementFlags.INLINED)); assert(element.is(CommonFlags.INLINED));
var type = element.type; var type = element.type;
switch ( switch (
!retainType && !retainType &&
@ -1913,8 +1883,7 @@ export class Compiler extends DiagnosticEmitter {
expr = this.compileElementAccessExpression(<ElementAccessExpression>expression, contextualType); expr = this.compileElementAccessExpression(<ElementAccessExpression>expression, contextualType);
break; break;
} }
case NodeKind.FUNCTION: case NodeKind.FUNCTION: {
case NodeKind.FUNCTIONARROW: {
expr = this.compileFunctionExpression(<FunctionExpression>expression, contextualType); expr = this.compileFunctionExpression(<FunctionExpression>expression, contextualType);
break; break;
} }
@ -2582,7 +2551,7 @@ export class Compiler extends DiagnosticEmitter {
} else { } else {
this.error( this.error(
DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2,
expression.range, Token.operatorToString(expression.operator), leftType.toString(), rightType.toString() expression.range, operatorTokenToString(expression.operator), leftType.toString(), rightType.toString()
); );
this.currentType = contextualType; this.currentType = contextualType;
return module.createUnreachable(); return module.createUnreachable();
@ -2648,7 +2617,7 @@ export class Compiler extends DiagnosticEmitter {
} else { } else {
this.error( this.error(
DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2,
expression.range, Token.operatorToString(expression.operator), leftType.toString(), rightType.toString() expression.range, operatorTokenToString(expression.operator), leftType.toString(), rightType.toString()
); );
this.currentType = contextualType; this.currentType = contextualType;
return module.createUnreachable(); return module.createUnreachable();
@ -3183,7 +3152,7 @@ export class Compiler extends DiagnosticEmitter {
case TypeKind.F64: { case TypeKind.F64: {
this.error( this.error(
DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1,
expression.range, Token.operatorToString(expression.operator), this.currentType.toString() expression.range, operatorTokenToString(expression.operator), this.currentType.toString()
); );
return module.createUnreachable(); return module.createUnreachable();
} }
@ -3257,7 +3226,7 @@ export class Compiler extends DiagnosticEmitter {
case TypeKind.F64: { case TypeKind.F64: {
this.error( this.error(
DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1, DiagnosticCode.The_0_operator_cannot_be_applied_to_type_1,
expression.range, Token.operatorToString(expression.operator), this.currentType.toString() expression.range, operatorTokenToString(expression.operator), this.currentType.toString()
); );
return module.createUnreachable(); return module.createUnreachable();
} }
@ -3739,7 +3708,7 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) { switch (element.kind) {
case ElementKind.LOCAL: { case ElementKind.LOCAL: {
this.currentType = tee ? (<Local>element).type : Type.void; this.currentType = tee ? (<Local>element).type : Type.void;
if ((<Local>element).is(ElementFlags.CONSTANT)) { if ((<Local>element).is(CommonFlags.CONST)) {
this.error( this.error(
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
expression.range, (<Local>element).internalName expression.range, (<Local>element).internalName
@ -3755,7 +3724,7 @@ export class Compiler extends DiagnosticEmitter {
let type = (<Global>element).type; let type = (<Global>element).type;
assert(type != Type.void); assert(type != Type.void);
this.currentType = tee ? type : Type.void; this.currentType = tee ? type : Type.void;
if ((<Local>element).is(ElementFlags.CONSTANT)) { if ((<Local>element).is(CommonFlags.CONST)) {
this.error( this.error(
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
expression.range, expression.range,
@ -3775,7 +3744,7 @@ export class Compiler extends DiagnosticEmitter {
} }
} }
case ElementKind.FIELD: { case ElementKind.FIELD: {
if ((<Field>element).prototype.isReadonly) { if ((<Field>element).is(CommonFlags.READONLY)) {
this.error( this.error(
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
expression.range, (<Field>element).internalName expression.range, (<Field>element).internalName
@ -3823,7 +3792,7 @@ export class Compiler extends DiagnosticEmitter {
// call just the setter if the return value isn't of interest // call just the setter if the return value isn't of interest
if (!tee) { if (!tee) {
if (setterInstance.is(ElementFlags.INSTANCE)) { if (setterInstance.is(CommonFlags.INSTANCE)) {
assert(resolved.isInstanceTarget); assert(resolved.isInstanceTarget);
let thisArg = this.compileExpression( let thisArg = this.compileExpression(
<Expression>resolved.targetExpression, <Expression>resolved.targetExpression,
@ -3842,7 +3811,7 @@ export class Compiler extends DiagnosticEmitter {
if (!getterInstance) return module.createUnreachable(); if (!getterInstance) return module.createUnreachable();
let returnType = getterInstance.signature.returnType; let returnType = getterInstance.signature.returnType;
let nativeReturnType = returnType.toNativeType(); let nativeReturnType = returnType.toNativeType();
if (setterInstance.is(ElementFlags.INSTANCE)) { if (setterInstance.is(CommonFlags.INSTANCE)) {
assert(resolved.isInstanceTarget); assert(resolved.isInstanceTarget);
let thisArg = this.compileExpression( let thisArg = this.compileExpression(
<Expression>resolved.targetExpression, <Expression>resolved.targetExpression,
@ -3956,7 +3925,7 @@ export class Compiler extends DiagnosticEmitter {
let prototype = <FunctionPrototype>element; let prototype = <FunctionPrototype>element;
// builtins are compiled on the fly // builtins are compiled on the fly
if (prototype.is(ElementFlags.BUILTIN)) { if (prototype.is(CommonFlags.BUILTIN)) {
let expr = compileBuiltinCall( // reports let expr = compileBuiltinCall( // reports
this, this,
prototype, prototype,
@ -3986,7 +3955,7 @@ export class Compiler extends DiagnosticEmitter {
); );
if (!instance) return module.createUnreachable(); if (!instance) return module.createUnreachable();
let thisArg: ExpressionRef = 0; let thisArg: ExpressionRef = 0;
if (instance.is(ElementFlags.INSTANCE)) { if (instance.is(CommonFlags.INSTANCE)) {
assert(resolved.isInstanceTarget); assert(resolved.isInstanceTarget);
thisArg = this.compileExpression( thisArg = this.compileExpression(
<Expression>resolved.targetExpression, <Expression>resolved.targetExpression,
@ -4174,7 +4143,7 @@ export class Compiler extends DiagnosticEmitter {
var originalParameterDeclarations = original.prototype.declaration.signature.parameterTypes; var originalParameterDeclarations = original.prototype.declaration.signature.parameterTypes;
var commonReturnType = originalSignature.returnType; var commonReturnType = originalSignature.returnType;
var commonThisType = originalSignature.thisType; var commonThisType = originalSignature.thisType;
var isInstance = original.is(ElementFlags.INSTANCE); var isInstance = original.is(CommonFlags.INSTANCE);
// arguments excl. `this`, operands incl. `this` // arguments excl. `this`, operands incl. `this`
var minArguments = originalSignature.requiredParameters; var minArguments = originalSignature.requiredParameters;
@ -4216,7 +4185,8 @@ export class Compiler extends DiagnosticEmitter {
var trampolineName = originalName + "|trampoline"; var trampolineName = originalName + "|trampoline";
trampolineSignature.requiredParameters = maxArguments + 1; trampolineSignature.requiredParameters = maxArguments + 1;
trampoline = new Function(original.prototype, trampolineName, trampolineSignature, original.instanceMethodOf); trampoline = new Function(original.prototype, trampolineName, trampolineSignature, original.instanceMethodOf);
trampoline.flags = original.flags | ElementFlags.COMPILED; trampoline.flags = original.flags;
trampoline.set(CommonFlags.COMPILED);
original.trampoline = trampoline; original.trampoline = trampoline;
// compile initializers of omitted arguments in scope of the trampoline function // compile initializers of omitted arguments in scope of the trampoline function
@ -4278,7 +4248,7 @@ export class Compiler extends DiagnosticEmitter {
var minOperands = minArguments; var minOperands = minArguments;
var maxArguments = instance.signature.parameterTypes.length; var maxArguments = instance.signature.parameterTypes.length;
var maxOperands = maxArguments; var maxOperands = maxArguments;
if (instance.is(ElementFlags.INSTANCE)) { if (instance.is(CommonFlags.INSTANCE)) {
++minOperands; ++minOperands;
++maxOperands; ++maxOperands;
--numArguments; --numArguments;
@ -4300,7 +4270,7 @@ export class Compiler extends DiagnosticEmitter {
} }
var returnType = instance.signature.returnType; var returnType = instance.signature.returnType;
this.currentType = returnType; this.currentType = returnType;
if (instance.is(ElementFlags.IMPORTED)) { if (instance.is(CommonFlags.MODULE_IMPORT)) {
return module.createCallImport(instance.internalName, operands, returnType.toNativeType()); return module.createCallImport(instance.internalName, operands, returnType.toNativeType());
} else { } else {
return module.createCall(instance.internalName, operands, returnType.toNativeType()); return module.createCall(instance.internalName, operands, returnType.toNativeType());
@ -4445,7 +4415,7 @@ export class Compiler extends DiagnosticEmitter {
} }
case NodeKind.THIS: { case NodeKind.THIS: {
let currentFunction = this.currentFunction; let currentFunction = this.currentFunction;
if (currentFunction.is(ElementFlags.INSTANCE)) { if (currentFunction.is(CommonFlags.INSTANCE)) {
let thisType = assert(currentFunction.instanceMethodOf).type; let thisType = assert(currentFunction.instanceMethodOf).type;
this.currentType = thisType; this.currentType = thisType;
return module.createGetLocal(0, thisType.toNativeType()); return module.createGetLocal(0, thisType.toNativeType());
@ -4459,7 +4429,7 @@ export class Compiler extends DiagnosticEmitter {
} }
case NodeKind.SUPER: { case NodeKind.SUPER: {
let currentFunction = this.currentFunction; let currentFunction = this.currentFunction;
if (currentFunction.is(ElementFlags.INSTANCE)) { if (currentFunction.is(CommonFlags.INSTANCE)) {
let base = assert(currentFunction.instanceMethodOf).base; let base = assert(currentFunction.instanceMethodOf).base;
if (base) { if (base) {
let superType = base.type; let superType = base.type;
@ -4487,7 +4457,7 @@ export class Compiler extends DiagnosticEmitter {
var element = resolved.element; var element = resolved.element;
switch (element.kind) { switch (element.kind) {
case ElementKind.LOCAL: { case ElementKind.LOCAL: {
if ((<Local>element).is(ElementFlags.INLINED)) { if ((<Local>element).is(CommonFlags.INLINED)) {
return this.compileInlineConstant(<Local>element, contextualType, retainConstantType); return this.compileInlineConstant(<Local>element, contextualType, retainConstantType);
} }
let localType = (<Local>element).type; let localType = (<Local>element).type;
@ -4497,7 +4467,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createGetLocal(localIndex, localType.toNativeType()); return this.module.createGetLocal(localIndex, localType.toNativeType());
} }
case ElementKind.GLOBAL: { case ElementKind.GLOBAL: {
if (element.is(ElementFlags.BUILTIN)) { if (element.is(CommonFlags.BUILTIN)) {
return compileBuiltinGetConstant(this, <Global>element, expression); return compileBuiltinGetConstant(this, <Global>element, expression);
} }
if (!this.compileGlobal(<Global>element)) { // reports; not yet compiled if a static field if (!this.compileGlobal(<Global>element)) { // reports; not yet compiled if a static field
@ -4505,14 +4475,14 @@ export class Compiler extends DiagnosticEmitter {
} }
let globalType = (<Global>element).type; let globalType = (<Global>element).type;
assert(globalType != Type.void); assert(globalType != Type.void);
if ((<Global>element).is(ElementFlags.INLINED)) { if ((<Global>element).is(CommonFlags.INLINED)) {
return this.compileInlineConstant(<Global>element, contextualType, retainConstantType); return this.compileInlineConstant(<Global>element, contextualType, retainConstantType);
} }
this.currentType = globalType; this.currentType = globalType;
return this.module.createGetGlobal((<Global>element).internalName, globalType.toNativeType()); return this.module.createGetGlobal((<Global>element).internalName, globalType.toNativeType());
} }
case ElementKind.ENUMVALUE: { // here: if referenced from within the same enum case ElementKind.ENUMVALUE: { // here: if referenced from within the same enum
if (!element.is(ElementFlags.COMPILED)) { if (!element.is(CommonFlags.COMPILED)) {
this.error( this.error(
DiagnosticCode.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums, DiagnosticCode.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums,
expression.range expression.range
@ -4521,7 +4491,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
this.currentType = Type.i32; this.currentType = Type.i32;
if ((<EnumValue>element).is(ElementFlags.INLINED)) { if ((<EnumValue>element).is(CommonFlags.INLINED)) {
return this.module.createI32((<EnumValue>element).constantValue); return this.module.createI32((<EnumValue>element).constantValue);
} }
return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32); return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
@ -4547,7 +4517,7 @@ export class Compiler extends DiagnosticEmitter {
let classType = contextualType.classType; let classType = contextualType.classType;
if ( if (
classType && classType &&
classType == this.program.elements.get("Array") && classType == this.program.elementsLookup.get("Array") &&
classType.typeArguments && classType.typeArguments.length == 1 classType.typeArguments && classType.typeArguments.length == 1
) { ) {
return this.compileStaticArray( return this.compileStaticArray(
@ -4698,7 +4668,7 @@ export class Compiler extends DiagnosticEmitter {
stringSegments.set(stringValue, stringSegment); stringSegments.set(stringValue, stringSegment);
} }
var stringOffset = stringSegment.offset; var stringOffset = stringSegment.offset;
var stringType = this.program.types.get("string"); var stringType = this.program.typesLookup.get("string");
this.currentType = stringType ? stringType : options.usizeType; this.currentType = stringType ? stringType : options.usizeType;
if (options.isWasm64) { if (options.isWasm64) {
return module.createI64(i64_low(stringOffset), i64_high(stringOffset)); return module.createI64(i64_low(stringOffset), i64_high(stringOffset));
@ -4825,7 +4795,7 @@ export class Compiler extends DiagnosticEmitter {
if (member.kind == ElementKind.FIELD) { if (member.kind == ElementKind.FIELD) {
let field = <Field>member; let field = <Field>member;
let fieldDeclaration = field.prototype.declaration; let fieldDeclaration = field.prototype.declaration;
if (field.is(ElementFlags.CONSTANT)) { if (field.is(CommonFlags.CONST)) {
assert(false); // there are no built-in fields currently assert(false); // there are no built-in fields currently
} else if (fieldDeclaration && fieldDeclaration.initializer) { } else if (fieldDeclaration && fieldDeclaration.initializer) {
initializers.push(module.createStore(field.type.byteSize, initializers.push(module.createStore(field.type.byteSize,
@ -4899,7 +4869,7 @@ export class Compiler extends DiagnosticEmitter {
var targetExpr: ExpressionRef; var targetExpr: ExpressionRef;
switch (element.kind) { switch (element.kind) {
case ElementKind.GLOBAL: { // static property case ElementKind.GLOBAL: { // static property
if (element.is(ElementFlags.BUILTIN)) { if (element.is(CommonFlags.BUILTIN)) {
return compileBuiltinGetConstant(this, <Global>element, propertyAccess); return compileBuiltinGetConstant(this, <Global>element, propertyAccess);
} }
if (!this.compileGlobal(<Global>element)) { // reports; not yet compiled if a static field if (!this.compileGlobal(<Global>element)) { // reports; not yet compiled if a static field
@ -4907,7 +4877,7 @@ export class Compiler extends DiagnosticEmitter {
} }
let globalType = (<Global>element).type; let globalType = (<Global>element).type;
assert(globalType != Type.void); assert(globalType != Type.void);
if ((<Global>element).is(ElementFlags.INLINED)) { if ((<Global>element).is(CommonFlags.INLINED)) {
return this.compileInlineConstant(<Global>element, contextualType, retainConstantType); return this.compileInlineConstant(<Global>element, contextualType, retainConstantType);
} }
this.currentType = globalType; this.currentType = globalType;
@ -4918,7 +4888,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
this.currentType = Type.i32; this.currentType = Type.i32;
if ((<EnumValue>element).is(ElementFlags.INLINED)) { if ((<EnumValue>element).is(CommonFlags.INLINED)) {
return module.createI32((<EnumValue>element).constantValue); return module.createI32((<EnumValue>element).constantValue);
} }
return module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32); return module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
@ -4949,7 +4919,7 @@ export class Compiler extends DiagnosticEmitter {
if (!this.checkCallSignature( // reports if (!this.checkCallSignature( // reports
signature, signature,
0, 0,
instance.is(ElementFlags.INSTANCE), instance.is(CommonFlags.INSTANCE),
propertyAccess propertyAccess
)) { )) {
return module.createUnreachable(); return module.createUnreachable();

478
src/definitions.ts Normal file
View File

@ -0,0 +1,478 @@
/**
* @file Definition builders for WebIDL and TypeScript.
*/
import {
Program,
Element,
CommonFlags,
ElementKind,
Global,
Enum,
EnumValue,
Function,
Class,
Namespace,
FunctionPrototype,
ClassPrototype,
ConstantValueKind,
Interface
} from "./program";
import {
Type,
TypeKind
} from "./types";
import {
indent
} from "./util/text";
/** Walker base class. */
abstract class ExportsWalker {
/** Program reference. */
program: Program;
/** Constructs a new Element walker. */
constructor(program: Program) {
this.program = program;
}
walk(): void {
for (let element of this.program.moduleLevelExports.values()) {
this.visitElement(element);
}
}
visitElement(element: Element): void {
switch (element.kind) {
case ElementKind.GLOBAL: {
if (element.is(CommonFlags.COMPILED)) {
this.visitGlobal(<Global>element);
}
break;
}
case ElementKind.ENUM: {
if (element.is(CommonFlags.COMPILED)) {
this.visitEnum(<Enum>element);
}
break;
}
case ElementKind.FUNCTION_PROTOTYPE: {
for (let instance of (<FunctionPrototype>element).instances.values()) {
if (instance.is(CommonFlags.COMPILED)) {
this.visitFunction(<Function>instance);
}
}
break;
}
case ElementKind.CLASS_PROTOTYPE: {
for (let instance of (<ClassPrototype>element).instances.values()) {
if (instance.is(CommonFlags.COMPILED)) {
this.visitClass(<Class>instance);
}
}
break;
}
case ElementKind.NAMESPACE: {
if ((<Namespace>element).is(CommonFlags.COMPILED)) {
this.visitNamespace(<Namespace>element);
}
break;
}
default: {
assert(false);
break;
}
}
}
abstract visitGlobal(element: Global): void;
abstract visitEnum(element: Enum): void;
abstract visitFunction(element: Function): void;
abstract visitClass(element: Class): void;
abstract visitInterface(element: Interface): void;
abstract visitNamespace(element: Element): void;
}
/** A WebIDL definitions builder. */
export class IDLBuilder extends ExportsWalker {
/** Builds WebIDL definitions for the specified program. */
static build(program: Program): string {
return new IDLBuilder(program).build();
}
private sb: string[] = [];
private seen: Set<Element> = new Set();
private indentLevel: i32 = 0;
/** Constructs a new WebIDL builder. */
constructor(program: Program) {
super(program);
}
visitGlobal(element: Global): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
var isConst = element.is(CommonFlags.INLINED);
indent(sb, this.indentLevel);
if (isConst) {
sb.push("const ");
}
sb.push(this.typeToString(element.type));
sb.push(" ");
sb.push(element.simpleName);
if (isConst) {
switch (element.constantValueKind) {
case ConstantValueKind.INTEGER: {
sb.push(" = ");
sb.push(i64_to_string(element.constantIntegerValue));
break;
}
case ConstantValueKind.FLOAT: {
sb.push(" = ");
sb.push(element.constantFloatValue.toString());
break;
}
default: assert(false);
}
}
sb.push(";\n");
}
visitEnum(element: Enum): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
indent(sb, this.indentLevel++);
sb.push("interface ");
sb.push(element.simpleName);
sb.push(" {\n");
var members = element.members;
if (members) {
for (let [name, member] of members) {
if (member.kind == ElementKind.ENUMVALUE) {
let isConst = (<EnumValue>member).is(CommonFlags.INLINED);
indent(sb, this.indentLevel);
if (isConst) {
sb.push("const ");
} else {
sb.push("readonly ");
}
sb.push("unsigned long ");
sb.push(name);
if (isConst) {
sb.push(" = ");
sb.push((<EnumValue>member).constantValue.toString(10));
}
sb.push(";\n");
}
}
for (let member of members.values()) {
if (member.kind != ElementKind.ENUMVALUE) {
this.visitElement(member);
}
}
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
visitFunction(element: Function): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
var signature = element.signature;
indent(sb, this.indentLevel);
sb.push(this.typeToString(signature.returnType));
sb.push(" ");
sb.push(element.simpleName);
sb.push("(");
var parameters = signature.parameterTypes;
var numParameters = parameters.length;
// var requiredParameters = signature.requiredParameters;
for (let i = 0; i < numParameters; ++i) {
if (i) sb.push(", ");
// if (i >= requiredParameters) sb.push("optional ");
sb.push(this.typeToString(parameters[i]));
sb.push(" ");
sb.push(signature.getParameterName(i));
}
sb.push(");\n");
var members = element.members;
if (members && members.size) {
indent(sb, this.indentLevel);
sb.push("interface ");
sb.push(element.simpleName);
sb.push(" {\n");
for (let member of members.values()) {
this.visitElement(member);
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
}
visitClass(element: Class): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
indent(sb, this.indentLevel++);
sb.push("interface ");
sb.push(element.simpleName);
sb.push(" {\n");
// TODO
indent(sb, --this.indentLevel);
sb.push("}\n");
}
visitInterface(element: Interface): void {
this.visitClass(element);
}
visitNamespace(element: Namespace): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
indent(sb, this.indentLevel++);
sb.push("interface ");
sb.push(element.simpleName);
sb.push(" {\n");
var members = element.members;
if (members) {
for (let member of members.values()) {
this.visitElement(member);
}
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
typeToString(type: Type): string {
switch (type.kind) {
case TypeKind.I8: return "byte";
case TypeKind.I16: return "short";
case TypeKind.I32: return "long";
case TypeKind.I64: return "long long";
case TypeKind.ISIZE: return this.program.options.isWasm64 ? "long long" : "long";
case TypeKind.U8: return "octet";
case TypeKind.U16: return "unsigned short";
case TypeKind.U32: return "unsigned long";
// ^ TODO: function types
case TypeKind.U64: return "unsigned long long";
case TypeKind.USIZE: return this.program.options.isWasm64 ? "unsigned long long" : "unsigned long";
// ^ TODO: class types
case TypeKind.BOOL: return "boolean";
case TypeKind.F32: return "unrestricted float";
case TypeKind.F64: return "unrestricted double";
case TypeKind.VOID: return "void";
default: {
assert(false);
return "";
}
}
}
build(): string {
var sb = this.sb;
sb.push("interface ASModule {\n");
++this.indentLevel;
this.walk();
--this.indentLevel;
sb.push("}\n");
return sb.join("");
}
}
/** A TypeScript definitions builder. */
export class TSDBuilder extends ExportsWalker {
/** Builds TypeScript definitions for the specified program. */
static build(program: Program): string {
return new TSDBuilder(program).build();
}
private sb: string[] = [];
private seen: Set<Element> = new Set();
private indentLevel: i32 = 0;
/** Constructs a new WebIDL builder. */
constructor(program: Program) {
super(program);
}
visitGlobal(element: Global): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
var isConst = element.is(CommonFlags.INLINED);
indent(sb, this.indentLevel);
if (isConst) {
sb.push("const ");
}
sb.push(element.simpleName);
sb.push(": ");
sb.push(this.typeToString(element.type));
sb.push(";\n");
this.visitNamespace(element);
}
visitEnum(element: Enum): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
indent(sb, this.indentLevel++);
sb.push("enum ");
sb.push(element.simpleName);
sb.push(" {\n");
var members = element.members;
if (members) {
let numMembers = members.size;
for (let [name, member] of members) {
if (member.kind == ElementKind.ENUMVALUE) {
this.seen.add(member);
indent(sb, this.indentLevel);
sb.push(name);
if (member.is(CommonFlags.INLINED)) {
sb.push(" = ");
sb.push((<EnumValue>member).constantValue.toString(10));
}
sb.push(",\n");
--numMembers;
}
}
if (numMembers) {
this.visitNamespace(element);
}
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
visitFunction(element: Function): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
var signature = element.signature;
indent(sb, this.indentLevel);
sb.push("function ");
sb.push(element.simpleName);
sb.push("(");
var parameters = signature.parameterTypes;
var numParameters = parameters.length;
// var requiredParameters = signature.requiredParameters;
for (let i = 0; i < numParameters; ++i) {
if (i) sb.push(", ");
// if (i >= requiredParameters) sb.push("optional ");
sb.push(signature.getParameterName(i));
sb.push(": ");
sb.push(this.typeToString(parameters[i]));
}
sb.push("): ");
sb.push(this.typeToString(signature.returnType));
sb.push(";\n");
this.visitNamespace(element);
}
visitClass(element: Class): void {
if (this.seen.has(element)) return;
this.seen.add(element);
var sb = this.sb;
var isInterface = element.kind == ElementKind.INTERFACE;
indent(sb, this.indentLevel++);
if (isInterface) {
sb.push("interface ");
} else {
if (element.is(CommonFlags.ABSTRACT)) {
sb.push("abstract ");
}
sb.push("class ");
}
sb.push(element.simpleName);
var base = element.base;
if (base) {
sb.push(" extends ");
sb.push(base.simpleName); // TODO: fqn
}
sb.push(" {\n");
var members = element.prototype.members; // static
if (members) {
// TODO
}
members = element.members; // instance
if (members) {
// TODO
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
visitInterface(element: Interface): void {
this.visitClass(element);
}
visitNamespace(element: Element): void {
var members = element.members;
if (members && members.size) {
let sb = this.sb;
indent(sb, this.indentLevel++);
sb.push("namespace ");
sb.push(element.simpleName);
sb.push(" {\n");
for (let member of members.values()) {
this.visitElement(member);
}
indent(sb, --this.indentLevel);
sb.push("}\n");
}
}
typeToString(type: Type): string {
switch (type.kind) {
case TypeKind.I8: return "i8";
case TypeKind.I16: return "i16";
case TypeKind.I32: return "i32";
case TypeKind.I64: return "I64";
case TypeKind.ISIZE: return this.program.options.isWasm64 ? "I64" : "i32";
case TypeKind.U8: return "u8";
case TypeKind.U16: return "u16";
case TypeKind.U32: return "u32";
// ^ TODO: function types
case TypeKind.U64: return "U64";
case TypeKind.USIZE: return this.program.options.isWasm64 ? "U64" : "u32";
// ^ TODO: class types
case TypeKind.BOOL: return "bool";
case TypeKind.F32: return "f32";
case TypeKind.F64: return "f64";
case TypeKind.VOID: return "void";
default: {
assert(false);
return "";
}
}
}
build(): string {
var sb = this.sb;
sb.push("declare module ASModule {\n");
sb.push(" type i8 = number;\n");
sb.push(" type i16 = number;\n");
sb.push(" type i32 = number;\n");
sb.push(" type u8 = number;\n");
sb.push(" type u16 = number;\n");
sb.push(" type u32 = number;\n");
sb.push(" type f32 = number;\n");
sb.push(" type f64 = number;\n");
sb.push(" type bool = any;\n");
++this.indentLevel;
this.walk();
--this.indentLevel;
sb.push("}\n");
return this.sb.join("");
}
}
// TODO: C bindings? or is this sufficiently covered by WebIDL and using a 3rd-party tool?

View File

@ -51,6 +51,7 @@ export enum DiagnosticCode {
Unexpected_end_of_text = 1126, Unexpected_end_of_text = 1126,
Invalid_character = 1127, Invalid_character = 1127,
_case_or_default_expected = 1130, _case_or_default_expected = 1130,
A_declare_modifier_cannot_be_used_in_an_already_ambient_context = 1038,
Type_argument_expected = 1140, Type_argument_expected = 1140,
String_literal_expected = 1141, String_literal_expected = 1141,
Line_break_not_permitted_here = 1142, Line_break_not_permitted_here = 1142,
@ -150,6 +151,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1126: return "Unexpected end of text."; case 1126: return "Unexpected end of text.";
case 1127: return "Invalid character."; case 1127: return "Invalid character.";
case 1130: return "'case' or 'default' expected."; case 1130: return "'case' or 'default' expected.";
case 1038: return "A 'declare' modifier cannot be used in an already ambient context.";
case 1140: return "Type argument expected."; case 1140: return "Type argument expected.";
case 1141: return "String literal expected."; case 1141: return "String literal expected.";
case 1142: return "Line break not permitted here."; case 1142: return "Line break not permitted here.";

View File

@ -49,6 +49,7 @@
"Unexpected end of text.": 1126, "Unexpected end of text.": 1126,
"Invalid character.": 1127, "Invalid character.": 1127,
"'case' or 'default' expected.": 1130, "'case' or 'default' expected.": 1130,
"A 'declare' modifier cannot be used in an already ambient context.": 1038,
"Type argument expected.": 1140, "Type argument expected.": 1140,
"String literal expected.": 1141, "String literal expected.": 1141,
"Line break not permitted here.": 1142, "Line break not permitted here.": 1142,

View File

@ -111,10 +111,10 @@ export class DiagnosticMessage {
this.message + this.message +
"\" in " + "\" in " +
this.range.source.normalizedPath + this.range.source.normalizedPath +
" @ " + ":" +
this.range.start.toString(10) + this.range.line.toString(10) +
"," + ":" +
this.range.end.toString(10) this.range.column.toString(10)
); );
} }
return ( return (

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,11 @@ import {
Decompiler Decompiler
} from "./decompiler"; } from "./decompiler";
import {
IDLBuilder,
TSDBuilder
} from "./definitions";
import { import {
DiagnosticMessage, DiagnosticMessage,
DiagnosticCategory, DiagnosticCategory,
@ -24,6 +29,11 @@ import {
Parser Parser
} from "./parser"; } from "./parser";
import {
Program,
LIBRARY_PREFIX
} from "./program";
/** Parses a source file. If `parser` has been omitted a new one is created. */ /** Parses a source file. If `parser` has been omitted a new one is created. */
export function parseFile(text: string, path: string, isEntry: bool = false, export function parseFile(text: string, path: string, isEntry: bool = false,
parser: Parser | null = null parser: Parser | null = null
@ -107,19 +117,32 @@ export function setMemoryBase(options: Options, memoryBase: u32): void {
options.memoryBase = memoryBase; options.memoryBase = memoryBase;
} }
/** Finishes parsing. */
export function finishParsing(parser: Parser): Program {
return parser.finish();
}
/** Compiles the sources computed by the parser to a module. */ /** Compiles the sources computed by the parser to a module. */
export function compile(parser: Parser, options: Options | null = null): Module { export function compileProgram(program: Program, options: Options | null = null): Module {
var program = parser.finish(); return new Compiler(program, options).compile();
var compiler = new Compiler(program, options);
return compiler.compile();
} }
/** Decompiles a module to its (low level) source. */ /** Decompiles a module to its (low level) source. */
export function decompile(module: Module): string { export function decompileModule(module: Module): string {
var decompiler = new Decompiler(); var decompiler = new Decompiler();
decompiler.decompile(module); decompiler.decompile(module);
return decompiler.finish(); return decompiler.finish();
} }
/** Builds WebIDL definitions for the specified program. */
export function buildIDL(program: Program): string {
return IDLBuilder.build(program);
}
/** Builds TypeScript definitions for the specified program. */
export function buildTSD(program: Program): string {
return TSDBuilder.build(program);
}
/** Prefix indicating a library file. */ /** Prefix indicating a library file. */
export { LIBRARY_PREFIX } from "./program"; export { LIBRARY_PREFIX };

View File

@ -8,6 +8,7 @@
import { import {
Program, Program,
CommonFlags,
LIBRARY_PREFIX, LIBRARY_PREFIX,
PATH_DELIMITER PATH_DELIMITER
} from "./program"; } from "./program";
@ -63,8 +64,6 @@ import {
IfStatement, IfStatement,
ImportDeclaration, ImportDeclaration,
ImportStatement, ImportStatement,
ModifierNode,
ModifierKind,
NamespaceDeclaration, NamespaceDeclaration,
ParameterNode, ParameterNode,
ParameterKind, ParameterKind,
@ -78,13 +77,7 @@ import {
VariableStatement, VariableStatement,
VariableDeclaration, VariableDeclaration,
VoidStatement, VoidStatement,
WhileStatement, WhileStatement
addModifier,
getModifier,
hasModifier,
setReusableModifiers
} from "./ast"; } from "./ast";
/** Parser interface. */ /** Parser interface. */
@ -97,6 +90,9 @@ export class Parser extends DiagnosticEmitter {
/** Log of source file names already processed. */ /** Log of source file names already processed. */
seenlog: Set<string> = new Set(); seenlog: Set<string> = new Set();
currentDeclareStart: i32 = 0;
currentDeclareEnd: i32 = 0;
/** Constructs a new parser. */ /** Constructs a new parser. */
constructor() { constructor() {
super(); super();
@ -149,74 +145,95 @@ export class Parser extends DiagnosticEmitter {
tn: Tokenizer, tn: Tokenizer,
isNamespaceMember: bool = false isNamespaceMember: bool = false
): Statement | null { ): Statement | null {
var flags = CommonFlags.NONE;
var startPos: i32 = -1;
// check decorators // check decorators
var decorators: DecoratorNode[] | null = null; var decorators: DecoratorNode[] | null = null;
while (tn.skip(Token.AT)) { while (tn.skip(Token.AT)) {
if (startPos < 0) startPos = tn.tokenPos;
let decorator = this.parseDecorator(tn); let decorator = this.parseDecorator(tn);
if (!decorator) break; if (!decorator) break;
let name = decorator.name;
if (name.kind == NodeKind.IDENTIFIER) {
let text = (<IdentifierExpression>name).text;
if (text == "global") {
flags |= CommonFlags.GLOBAL;
continue;
}
if (text == "builtin") {
flags |= CommonFlags.BUILTIN;
continue;
}
if (text == "unmananged") {
flags |= CommonFlags.UNMANAGED;
continue;
}
}
if (!decorators) decorators = []; if (!decorators) decorators = [];
decorators.push(decorator); decorators.push(decorator);
} }
// check modifiers // check modifiers
var modifiers: ModifierNode[] | null = null; var exportStart: i32 = 0;
var exportEnd: i32 = 0;
if (tn.skip(Token.EXPORT)) { if (tn.skip(Token.EXPORT)) {
modifiers = addModifier(Node.createModifier(ModifierKind.EXPORT, tn.range()), modifiers); if (startPos < 0) startPos = tn.tokenPos;
flags |= CommonFlags.EXPORT;
exportStart = tn.tokenPos;
exportEnd = tn.pos;
} }
var declareStart: i32 = 0;
var declareEnd: i32 = 0;
if (tn.skip(Token.DECLARE)) { if (tn.skip(Token.DECLARE)) {
modifiers = addModifier(Node.createModifier(ModifierKind.DECLARE, tn.range()), modifiers); if (startPos < 0) startPos = tn.tokenPos;
tn.peek(true); flags |= CommonFlags.DECLARE;
if (tn.nextTokenOnNewLine) { this.currentDeclareStart = declareStart = tn.tokenPos;
this.error( this.currentDeclareEnd = declareEnd = tn.pos;
DiagnosticCode.Line_break_not_permitted_here,
tn.range(tn.pos)
); // recoverable, compatibility
}
} }
// parse the statement // parse the statement
var statement: Statement | null = null; var statement: Statement | null = null;
var modifier: ModifierNode | null;
// handle declarations // handle declarations
switch (tn.peek()) { var first = tn.peek();
if (startPos < 0) startPos = tn.nextTokenPos;
switch (first) {
case Token.CONST: { case Token.CONST: {
tn.next(); tn.next();
modifiers = addModifier(Node.createModifier(ModifierKind.CONST, tn.range()), modifiers); flags |= CommonFlags.CONST;
if (tn.skip(Token.ENUM)) { if (tn.skip(Token.ENUM)) {
statement = this.parseEnum(tn, modifiers, decorators); statement = this.parseEnum(tn, flags, decorators, startPos);
break; break;
} else { } else {
statement = this.parseVariable(tn, modifiers, decorators); statement = this.parseVariable(tn, flags, decorators, startPos);
decorators = null; decorators = null;
} }
break; break;
} }
case Token.LET: { case Token.LET: flags |= CommonFlags.LET;
modifiers = addModifier(Node.createModifier(ModifierKind.LET, tn.range()), modifiers);
// fall-through
}
case Token.VAR: { case Token.VAR: {
tn.next(); tn.next();
statement = this.parseVariable(tn, modifiers, decorators); statement = this.parseVariable(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
case Token.ENUM: { case Token.ENUM: {
tn.next(); tn.next();
statement = this.parseEnum(tn, modifiers, decorators); statement = this.parseEnum(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
case Token.FUNCTION: { case Token.FUNCTION: {
tn.next(); tn.next();
statement = this.parseFunction(tn, modifiers, decorators); statement = this.parseFunction(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
case Token.ABSTRACT: { case Token.ABSTRACT: {
tn.next(); tn.next();
flags |= CommonFlags.ABSTRACT;
if (!tn.skip(Token.CLASS)) { if (!tn.skip(Token.CLASS)) {
this.error( this.error(
DiagnosticCode._0_expected, DiagnosticCode._0_expected,
@ -224,55 +241,55 @@ export class Parser extends DiagnosticEmitter {
); );
break; break;
} }
modifiers = addModifier(
Node.createModifier(ModifierKind.ABSTRACT, tn.range()), modifiers
);
// fall through // fall through
} }
case Token.CLASS: { case Token.CLASS: {
tn.next(); tn.next();
statement = this.parseClass(tn, modifiers, decorators); statement = this.parseClass(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
case Token.NAMESPACE: { case Token.NAMESPACE: {
tn.next(); tn.next();
statement = this.parseNamespace(tn, modifiers, decorators); statement = this.parseNamespace(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
case Token.IMPORT: { case Token.IMPORT: {
tn.next(); tn.next();
if (modifier = getModifier(ModifierKind.EXPORT, modifiers)) { flags |= CommonFlags.IMPORT;
statement = this.parseExportImport(tn, modifier.range); if (flags & CommonFlags.EXPORT) {
statement = this.parseExportImport(tn, startPos);
} else { } else {
statement = this.parseImport(tn); statement = this.parseImport(tn);
} }
if (modifiers) setReusableModifiers(modifiers);
break; break;
} }
case Token.TYPE: { case Token.TYPE: {
tn.next(); tn.next();
statement = this.parseTypeDeclaration(tn, modifiers, decorators); statement = this.parseTypeDeclaration(tn, flags, decorators, startPos);
decorators = null; decorators = null;
break; break;
} }
default: { default: {
// handle plain exports // handle plain exports
if (hasModifier(ModifierKind.EXPORT, modifiers)) { if (flags & CommonFlags.EXPORT) {
statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again? 'declare'? statement = this.parseExport(tn, flags, startPos);
// handle non-declaration statements // handle non-declaration statements
} else { } else {
if (modifiers) { if (exportEnd) {
if (modifier = getModifier(ModifierKind.DECLARE, modifiers)) {
this.error( this.error(
DiagnosticCode._0_modifier_cannot_be_used_here, DiagnosticCode._0_modifier_cannot_be_used_here,
modifier.range, "declare" tn.range(exportStart, exportEnd), "export"
); // recoverable ); // recoverable
} }
setReusableModifiers(modifiers); if (declareEnd) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(declareStart, declareEnd), "declare"
); // recoverable
} }
if (!isNamespaceMember) { if (!isNamespaceMember) {
statement = this.parseStatement(tn, true); statement = this.parseStatement(tn, true);
@ -688,30 +705,28 @@ export class Parser extends DiagnosticEmitter {
parseVariable( parseVariable(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null, flags: CommonFlags,
decorators: DecoratorNode[] | null decorators: DecoratorNode[] | null,
startPos: i32
): VariableStatement | null { ): VariableStatement | null {
// at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'? // at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'?
var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
var members = new Array<VariableDeclaration>(); var members = new Array<VariableDeclaration>();
var isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do { do {
let member = this.parseVariableDeclaration(tn, isDeclare, modifiers, decorators); let member = this.parseVariableDeclaration(tn, flags, decorators);
if (!member) return null; if (!member) return null;
members.push(<VariableDeclaration>member); members.push(<VariableDeclaration>member);
} while (tn.skip(Token.COMMA)); } while (tn.skip(Token.COMMA));
var ret = Node.createVariableStatement(members, modifiers, decorators, tn.range(startPos, tn.pos)); var ret = Node.createVariableStatement(members, decorators, flags, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
return ret; return ret;
} }
parseVariableDeclaration( parseVariableDeclaration(
tn: Tokenizer, tn: Tokenizer,
isDeclare: bool = false, parentFlags: CommonFlags,
parentModifiers: ModifierNode[] | null,
parentDecorators: DecoratorNode[] | null parentDecorators: DecoratorNode[] | null
): VariableDeclaration | null { ): VariableDeclaration | null {
@ -725,6 +740,7 @@ export class Parser extends DiagnosticEmitter {
return null; return null;
} }
var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
var flags = parentFlags;
var type: CommonTypeNode | null = null; var type: CommonTypeNode | null = null;
if (tn.skip(Token.COLON)) { if (tn.skip(Token.COLON)) {
@ -733,7 +749,7 @@ export class Parser extends DiagnosticEmitter {
var initializer: Expression | null = null; var initializer: Expression | null = null;
if (tn.skip(Token.EQUALS)) { if (tn.skip(Token.EQUALS)) {
if (isDeclare) { if (flags & CommonFlags.AMBIENT) {
this.error( this.error(
DiagnosticCode.Initializers_are_not_allowed_in_ambient_contexts, DiagnosticCode.Initializers_are_not_allowed_in_ambient_contexts,
tn.range() tn.range()
@ -742,12 +758,12 @@ export class Parser extends DiagnosticEmitter {
initializer = this.parseExpression(tn, Precedence.COMMA + 1); initializer = this.parseExpression(tn, Precedence.COMMA + 1);
if (!initializer) return null; if (!initializer) return null;
} else { } else {
if (hasModifier(ModifierKind.CONST, parentModifiers)) { if (flags & CommonFlags.CONST) {
if (!hasModifier(ModifierKind.DECLARE, parentModifiers)) { if (!(flags & CommonFlags.DECLARE)) {
this.error( this.error(
DiagnosticCode._const_declarations_must_be_initialized, DiagnosticCode._const_declarations_must_be_initialized,
identifier.range identifier.range
); ); // recoverable
} }
} else if (!type) { // neither type nor initializer } else if (!type) { // neither type nor initializer
this.error( this.error(
@ -760,21 +776,21 @@ export class Parser extends DiagnosticEmitter {
identifier, identifier,
type, type,
initializer, initializer,
parentModifiers,
parentDecorators, parentDecorators,
flags,
Range.join(identifier.range, tn.range()) Range.join(identifier.range, tn.range())
); );
} }
parseEnum( parseEnum(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null, flags: CommonFlags,
decorators: DecoratorNode[] | null decorators: DecoratorNode[] | null,
startPos: i32
): EnumDeclaration | null { ): EnumDeclaration | null {
// at 'enum': Identifier '{' (EnumValueDeclaration (',' EnumValueDeclaration )*)? '}' ';'? // at 'enum': Identifier '{' (EnumValueDeclaration (',' EnumValueDeclaration )*)? '}' ';'?
var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (tn.next() != Token.IDENTIFIER) { if (tn.next() != Token.IDENTIFIER) {
this.error( this.error(
DiagnosticCode.Identifier_expected, DiagnosticCode.Identifier_expected,
@ -793,7 +809,7 @@ export class Parser extends DiagnosticEmitter {
var members = new Array<EnumValueDeclaration>(); var members = new Array<EnumValueDeclaration>();
if (!tn.skip(Token.CLOSEBRACE)) { if (!tn.skip(Token.CLOSEBRACE)) {
do { do {
let member = this.parseEnumValue(tn); let member = this.parseEnumValue(tn, CommonFlags.NONE);
if (!member) return null; if (!member) return null;
members.push(<EnumValueDeclaration>member); members.push(<EnumValueDeclaration>member);
} while (tn.skip(Token.COMMA)); } while (tn.skip(Token.COMMA));
@ -808,8 +824,8 @@ export class Parser extends DiagnosticEmitter {
var ret = Node.createEnumDeclaration( var ret = Node.createEnumDeclaration(
identifier, identifier,
members, members,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
@ -817,7 +833,8 @@ export class Parser extends DiagnosticEmitter {
} }
parseEnumValue( parseEnumValue(
tn: Tokenizer tn: Tokenizer,
parentFlags: CommonFlags
): EnumValueDeclaration | null { ): EnumValueDeclaration | null {
// before: Identifier ('=' Expression)? // before: Identifier ('=' Expression)?
@ -838,6 +855,7 @@ export class Parser extends DiagnosticEmitter {
return Node.createEnumValueDeclaration( return Node.createEnumValueDeclaration(
identifier, identifier,
value, value,
parentFlags,
Range.join(identifier.range, tn.range()) Range.join(identifier.range, tn.range())
); );
} }
@ -1054,8 +1072,9 @@ export class Parser extends DiagnosticEmitter {
parseFunction( parseFunction(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null, flags: CommonFlags,
decorators: DecoratorNode[] | null decorators: DecoratorNode[] | null,
startPos: i32
): FunctionDeclaration | null { ): FunctionDeclaration | null {
// at 'function': // at 'function':
@ -1065,8 +1084,6 @@ export class Parser extends DiagnosticEmitter {
// '{' Statement* '}' // '{' Statement* '}'
// ';'? // ';'?
var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (!tn.skip(Token.IDENTIFIER)) { if (!tn.skip(Token.IDENTIFIER)) {
this.error( this.error(
DiagnosticCode.Identifier_expected, DiagnosticCode.Identifier_expected,
@ -1083,6 +1100,7 @@ export class Parser extends DiagnosticEmitter {
signatureStart = tn.tokenPos; signatureStart = tn.tokenPos;
typeParameters = this.parseTypeParameters(tn); typeParameters = this.parseTypeParameters(tn);
if (!typeParameters) return null; if (!typeParameters) return null;
flags |= CommonFlags.GENERIC;
} }
if (!tn.skip(Token.OPENPAREN)) { if (!tn.skip(Token.OPENPAREN)) {
@ -1100,16 +1118,14 @@ export class Parser extends DiagnosticEmitter {
var parameters = this.parseParameters(tn); var parameters = this.parseParameters(tn);
if (!parameters) return null; if (!parameters) return null;
var isSetter = hasModifier(ModifierKind.SET, modifiers); var isSetter = (flags & CommonFlags.SET) != 0;
if (isSetter) { if (isSetter) {
if (parameters.length != 1) { if (parameters.length != 1) {
this.error( this.error(
DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter, DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter,
name.range name.range
); // recoverable ); // recoverable
} }
if (parameters.length && parameters[0].initializer) { if (parameters.length && parameters[0].initializer) {
this.error( this.error(
DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer,
@ -1118,17 +1134,18 @@ export class Parser extends DiagnosticEmitter {
} }
} }
var isGetter = hasModifier(ModifierKind.GET, modifiers); if (flags & CommonFlags.GET) {
if (isGetter && parameters.length) { if (parameters.length) {
this.error( this.error(
DiagnosticCode.A_get_accessor_cannot_have_parameters, DiagnosticCode.A_get_accessor_cannot_have_parameters,
name.range name.range
); // recoverable ); // recoverable
} }
}
var returnType: CommonTypeNode | null = null; var returnType: CommonTypeNode | null = null;
if (tn.skip(Token.COLON)) { if (tn.skip(Token.COLON)) {
returnType = this.parseType(tn, isSetter); returnType = this.parseType(tn, true, isSetter);
if (!returnType) return null; if (!returnType) return null;
} }
@ -1152,11 +1169,20 @@ export class Parser extends DiagnosticEmitter {
tn.range(signatureStart, tn.pos) tn.range(signatureStart, tn.pos)
); );
var isDeclare = hasModifier(ModifierKind.DECLARE, modifiers); if (flags & CommonFlags.DECLARE) {
if (flags & CommonFlags.AMBIENT) {
this.error(
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
tn.range(this.currentDeclareStart, this.currentDeclareEnd)
); // recoverable
} else {
flags |= CommonFlags.AMBIENT;
}
}
var body: Statement | null = null; var body: Statement | null = null;
if (tn.skip(Token.OPENBRACE)) { if (tn.skip(Token.OPENBRACE)) {
if (isDeclare) { if (flags & CommonFlags.AMBIENT) {
this.error( this.error(
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
tn.range() tn.range()
@ -1165,7 +1191,7 @@ export class Parser extends DiagnosticEmitter {
body = this.parseBlockStatement(tn, false); body = this.parseBlockStatement(tn, false);
if (!body) return null; if (!body) return null;
} else if (!isDeclare) { } else if (!(flags & CommonFlags.AMBIENT)) {
this.error( this.error(
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
tn.range(tn.pos) tn.range(tn.pos)
@ -1177,8 +1203,8 @@ export class Parser extends DiagnosticEmitter {
typeParameters, typeParameters,
signature, signature,
body, body,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
@ -1290,16 +1316,17 @@ export class Parser extends DiagnosticEmitter {
signature, signature,
body, body,
null, null,
null, isArrow ? CommonFlags.ARROW : CommonFlags.NONE,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
return Node.createFunctionExpression(declaration, isArrow); return Node.createFunctionExpression(declaration);
} }
parseClass( parseClass(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null, flags: CommonFlags,
decorators: DecoratorNode[] | null decorators: DecoratorNode[] | null,
startPos: i32
): ClassDeclaration | null { ): ClassDeclaration | null {
// at 'class': // at 'class':
@ -1309,28 +1336,29 @@ export class Parser extends DiagnosticEmitter {
// ('implements' Type (',' Type)*)? // ('implements' Type (',' Type)*)?
// '{' ClassMember* '}' // '{' ClassMember* '}'
var startPos = decorators && decorators.length if (!tn.skip(Token.IDENTIFIER)) {
? decorators[0].range.start this.error(
: modifiers && modifiers.length DiagnosticCode.Identifier_expected,
? modifiers[0].range.start tn.range()
: tn.tokenPos; );
return null;
}
if (tn.skip(Token.IDENTIFIER)) { var identifier = Node.createIdentifierExpression(
let identifier = Node.createIdentifierExpression(
tn.readIdentifier(), tn.readIdentifier(),
tn.range() tn.range()
); );
let typeParameters: TypeParameterNode[] | null; var typeParameters: TypeParameterNode[] | null;
if (tn.skip(Token.LESSTHAN)) { if (tn.skip(Token.LESSTHAN)) {
typeParameters = this.parseTypeParameters(tn); typeParameters = this.parseTypeParameters(tn);
if (!typeParameters) return null; if (!typeParameters) return null;
flags |= CommonFlags.GENERIC;
} else { } else {
typeParameters = []; typeParameters = [];
} }
let extendsType: TypeNode | null = null; var extendsType: TypeNode | null = null;
if (tn.skip(Token.EXTENDS)) { if (tn.skip(Token.EXTENDS)) {
let t = this.parseType(tn); let t = this.parseType(tn);
if (!t) return null; if (!t) return null;
@ -1344,7 +1372,7 @@ export class Parser extends DiagnosticEmitter {
extendsType = <TypeNode>t; extendsType = <TypeNode>t;
} }
let implementsTypes = new Array<TypeNode>(); var implementsTypes = new Array<TypeNode>();
if (tn.skip(Token.IMPLEMENTS)) { if (tn.skip(Token.IMPLEMENTS)) {
do { do {
let type = this.parseType(tn); let type = this.parseType(tn);
@ -1353,13 +1381,29 @@ export class Parser extends DiagnosticEmitter {
} while (tn.skip(Token.COMMA)); } while (tn.skip(Token.COMMA));
} }
if (tn.skip(Token.OPENBRACE)) { if (!tn.skip(Token.OPENBRACE)) {
this.error(
DiagnosticCode._0_expected,
tn.range(), "{"
);
return null;
}
let members = new Array<DeclarationStatement>(); if (flags & CommonFlags.DECLARE) {
if (flags & CommonFlags.AMBIENT) {
this.error(
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
tn.range(this.currentDeclareStart, this.currentDeclareEnd)
); // recoverable
} else {
flags |= CommonFlags.AMBIENT;
}
}
var members = new Array<DeclarationStatement>();
if (!tn.skip(Token.CLOSEBRACE)) { if (!tn.skip(Token.CLOSEBRACE)) {
let isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do { do {
let member = this.parseClassMember(tn, isDeclare); let member = this.parseClassMember(tn, flags);
if (!member) return null; if (!member) return null;
members.push(<DeclarationStatement>member); members.push(<DeclarationStatement>member);
} while (!tn.skip(Token.CLOSEBRACE)); } while (!tn.skip(Token.CLOSEBRACE));
@ -1370,34 +1414,21 @@ export class Parser extends DiagnosticEmitter {
extendsType, extendsType,
implementsTypes, implementsTypes,
members, members,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
} else {
this.error(
DiagnosticCode._0_expected,
tn.range(), "{"
);
}
} else {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
);
}
return null;
} }
parseClassMember( parseClassMember(
tn: Tokenizer, tn: Tokenizer,
parentIsDeclare: bool parentFlags: CommonFlags
): DeclarationStatement | null { ): DeclarationStatement | null {
// before: // before:
// ('public' | 'private' | 'protected')? // ('public' | 'private' | 'protected')?
// ('static' | 'abstract')? // ('static' | 'abstract')?
// 'readonly'?
// ('get' | 'set')? // ('get' | 'set')?
// Identifier ... // Identifier ...
@ -1410,66 +1441,131 @@ export class Parser extends DiagnosticEmitter {
decorators.push(<DecoratorNode>decorator); decorators.push(<DecoratorNode>decorator);
} }
var modifiers: ModifierNode[] | null = null; var flags = parentFlags & CommonFlags.AMBIENT; // inherit
if (tn.skip(Token.PUBLIC)) { if (tn.skip(Token.PUBLIC)) {
modifiers = addModifier(Node.createModifier(ModifierKind.PUBLIC, tn.range()), modifiers); flags |= CommonFlags.PUBLIC;
} else if (tn.skip(Token.PRIVATE)) { } else if (tn.skip(Token.PRIVATE)) {
modifiers = addModifier(Node.createModifier(ModifierKind.PRIVATE, tn.range()), modifiers); flags |= CommonFlags.PRIVATE;
} else if (tn.skip(Token.PROTECTED)) { } else if (tn.skip(Token.PROTECTED)) {
modifiers = addModifier(Node.createModifier(ModifierKind.PROTECTED, tn.range()), modifiers); flags |= CommonFlags.PROTECTED;
} }
var staticStart: i32 = 0;
var staticEnd: i32 = 0;
var abstractStart: i32 = 0;
var abstractEnd: i32 = 0;
if (tn.skip(Token.STATIC)) { if (tn.skip(Token.STATIC)) {
modifiers = addModifier(Node.createModifier(ModifierKind.STATIC, tn.range()), modifiers); flags |= CommonFlags.STATIC;
staticStart = tn.tokenPos;
staticEnd = tn.pos;
} else if (tn.skip(Token.ABSTRACT)) { } else if (tn.skip(Token.ABSTRACT)) {
modifiers = addModifier(Node.createModifier(ModifierKind.ABSTRACT, tn.range()), modifiers); flags |= (CommonFlags.ABSTRACT | CommonFlags.INSTANCE);
abstractStart = tn.tokenPos;
abstractEnd = tn.pos;
} else {
flags |= CommonFlags.INSTANCE;
} }
var readonlyStart: i32 = 0;
var readonlyEnd: i32 = 0;
if (tn.skip(Token.READONLY)) { if (tn.skip(Token.READONLY)) {
modifiers = addModifier(Node.createModifier(ModifierKind.READONLY, tn.range()), modifiers); flags |= CommonFlags.READONLY;
readonlyStart = tn.tokenPos;
readonlyEnd = tn.pos;
} }
// check if accessor: ('get' | 'set') ^\n Identifier // check if accessor: ('get' | 'set') ^\n Identifier
var state = tn.mark(); var state = tn.mark();
var isConstructor = false;
var isGetter = false; var isGetter = false;
var getStart: i32 = 0;
var getEnd: i32 = 0;
var isSetter = false; var isSetter = false;
var setStart: i32 = 0;
if (isGetter = tn.skip(Token.GET)) { var setEnd: i32 = 0;
if (tn.skip(Token.GET)) {
if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) { if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
modifiers = addModifier(Node.createModifier(ModifierKind.GET, tn.range()), modifiers); flags |= CommonFlags.GET;
isGetter = true;
setStart = tn.tokenPos;
setEnd = tn.pos;
if (flags & CommonFlags.READONLY) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(readonlyStart, readonlyEnd), "readonly"
); // recoverable
}
} else { } else {
tn.reset(state); tn.reset(state);
isGetter = false;
} }
} else if (tn.skip(Token.SET)) {
} else if (isSetter = tn.skip(Token.SET)) { // can't be both
if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) { if (tn.peek(true, true) == Token.IDENTIFIER && !tn.nextTokenOnNewLine) {
modifiers = addModifier(Node.createModifier(ModifierKind.SET, tn.range()), modifiers); flags |= CommonFlags.SET | CommonFlags.SET;
isSetter = true;
setStart = tn.tokenPos;
setEnd = tn.pos;
if (flags & CommonFlags.READONLY) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(readonlyStart, readonlyEnd), "readonly"
); // recoverable
}
} else { } else {
tn.reset(state); tn.reset(state);
isSetter = false; }
} else if (tn.skip(Token.CONSTRUCTOR)) {
flags |= CommonFlags.CONSTRUCTOR;
isConstructor = true;
if (flags & CommonFlags.STATIC) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(staticStart, staticEnd), "static"
); // recoverable
}
if (flags & CommonFlags.ABSTRACT) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(abstractStart, abstractEnd), "abstract"
); // recoverable
}
if (flags & CommonFlags.READONLY) {
this.error(
DiagnosticCode._0_modifier_cannot_be_used_here,
tn.range(readonlyStart, readonlyEnd), "readonly"
); // recoverable
} }
} }
var isConstructor = tn.skip(Token.CONSTRUCTOR); if (!isConstructor && !tn.skip(Token.IDENTIFIER)) {
if (isConstructor || tn.skip(Token.IDENTIFIER)) { this.error(
DiagnosticCode.Identifier_expected,
tn.range()
);
return null;
}
let name = isConstructor var name = isConstructor
? Node.createConstructorExpression(tn.range()) ? Node.createConstructorExpression(tn.range())
: Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); : Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
var typeParameters: TypeParameterNode[] | null = null;
let typeParameters: TypeParameterNode[] | null = null;
if (tn.skip(Token.LESSTHAN)) { if (tn.skip(Token.LESSTHAN)) {
let typeParametersStart = tn.tokenPos;
typeParameters = this.parseTypeParameters(tn);
if (!typeParameters) return null;
if (isConstructor) { if (isConstructor) {
this.error( this.error(
DiagnosticCode.Type_parameters_cannot_appear_on_a_constructor_declaration, DiagnosticCode.Type_parameters_cannot_appear_on_a_constructor_declaration,
tn.range() tn.range(typeParametersStart, tn.pos)
); // recoverable ); // recoverable
} else if (isGetter || isSetter) {
this.error(
DiagnosticCode.An_accessor_cannot_have_type_parameters,
tn.range(typeParametersStart, tn.pos)
); // recoverable
} else {
flags |= CommonFlags.GENERIC;
} }
typeParameters = this.parseTypeParameters(tn);
if (!typeParameters) return null;
} }
// method: '(' Parameters (':' Type)? '{' Statement* '}' ';'? // method: '(' Parameters (':' Type)? '{' Statement* '}' ';'?
@ -1478,14 +1574,14 @@ export class Parser extends DiagnosticEmitter {
let parameters = this.parseParameters(tn); let parameters = this.parseParameters(tn);
if (!parameters) return null; if (!parameters) return null;
if (isGetter && parameters.length) { if (isGetter) {
if (parameters.length) {
this.error( this.error(
DiagnosticCode.A_get_accessor_cannot_have_parameters, DiagnosticCode.A_get_accessor_cannot_have_parameters,
name.range name.range
); );
} }
} else if (isSetter) {
if (isSetter) {
if (parameters.length != 1) { if (parameters.length != 1) {
this.error( this.error(
DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter, DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter,
@ -1535,7 +1631,7 @@ export class Parser extends DiagnosticEmitter {
let body: Statement | null = null; let body: Statement | null = null;
if (tn.skip(Token.OPENBRACE)) { if (tn.skip(Token.OPENBRACE)) {
if (parentIsDeclare) { if (flags & CommonFlags.AMBIENT) {
this.error( this.error(
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
tn.range() tn.range()
@ -1543,7 +1639,7 @@ export class Parser extends DiagnosticEmitter {
} }
body = this.parseBlockStatement(tn, false); body = this.parseBlockStatement(tn, false);
if (!body) return null; if (!body) return null;
} else if (!parentIsDeclare) { } else if (!(flags & CommonFlags.AMBIENT)) {
this.error( this.error(
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
tn.range() tn.range()
@ -1555,8 +1651,8 @@ export class Parser extends DiagnosticEmitter {
typeParameters, typeParameters,
signature, signature,
body, body,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
@ -1576,26 +1672,24 @@ export class Parser extends DiagnosticEmitter {
// field: (':' Type)? ('=' Expression)? ';'? // field: (':' Type)? ('=' Expression)? ';'?
} else { } else {
let modifier: ModifierNode | null; if (flags & CommonFlags.ABSTRACT) {
if (modifier = getModifier(ModifierKind.ABSTRACT, modifiers)) {
this.error( this.error(
DiagnosticCode._0_modifier_cannot_be_used_here, DiagnosticCode._0_modifier_cannot_be_used_here,
modifier.range, "abstract" tn.range(abstractStart, abstractEnd), "abstract"
); // recoverable ); // recoverable
} }
if (modifier = getModifier(ModifierKind.GET, modifiers)) { if (flags & CommonFlags.GET) {
this.error( this.error(
DiagnosticCode._0_modifier_cannot_be_used_here, DiagnosticCode._0_modifier_cannot_be_used_here,
modifier.range, "get" tn.range(getStart, getEnd), "get"
); // recoverable ); // recoverable
} }
if (modifier = getModifier(ModifierKind.SET, modifiers)) { if (flags & CommonFlags.SET) {
this.error( this.error(
DiagnosticCode._0_modifier_cannot_be_used_here, DiagnosticCode._0_modifier_cannot_be_used_here,
modifier.range, "set" tn.range(setStart, setEnd), "set"
); // recoverable ); // recoverable
} }
@ -1618,31 +1712,25 @@ export class Parser extends DiagnosticEmitter {
name, name,
type, type,
initializer, initializer,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
return retField; return retField;
} }
} else {
this.error(
DiagnosticCode.Identifier_expected,
tn.range()
);
}
return null; return null;
} }
parseNamespace( parseNamespace(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null, flags: CommonFlags,
decorators: DecoratorNode[] | null decorators: DecoratorNode[] | null,
startPos: i32
): NamespaceDeclaration | null { ): NamespaceDeclaration | null {
// at 'namespace': Identifier '{' (Variable | Function)* '}' // at 'namespace': Identifier '{' (Variable | Function)* '}'
var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (tn.skip(Token.IDENTIFIER)) { if (tn.skip(Token.IDENTIFIER)) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
if (tn.skip(Token.OPENBRACE)) { if (tn.skip(Token.OPENBRACE)) {
@ -1655,8 +1743,8 @@ export class Parser extends DiagnosticEmitter {
let ret = Node.createNamespaceDeclaration( let ret = Node.createNamespaceDeclaration(
identifier, identifier,
members, members,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
@ -1678,13 +1766,12 @@ export class Parser extends DiagnosticEmitter {
parseExport( parseExport(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null flags: CommonFlags,
startPos: i32
): ExportStatement | null { ): ExportStatement | null {
// at 'export': '{' ExportMember (',' ExportMember)* }' ('from' StringLiteral)? ';'? // at 'export': '{' ExportMember (',' ExportMember)* }' ('from' StringLiteral)? ';'?
var startPos = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (tn.skip(Token.OPENBRACE)) { if (tn.skip(Token.OPENBRACE)) {
let members = new Array<ExportMember>(); let members = new Array<ExportMember>();
if (!tn.skip(Token.CLOSEBRACE)) { if (!tn.skip(Token.CLOSEBRACE)) {
@ -1713,7 +1800,7 @@ export class Parser extends DiagnosticEmitter {
return null; return null;
} }
} }
let ret = Node.createExportStatement(members, path, modifiers, tn.range(startPos, tn.pos)); let ret = Node.createExportStatement(members, path, flags, tn.range(startPos, tn.pos));
if (ret.normalizedPath && !this.seenlog.has(<string>ret.normalizedPath)) { if (ret.normalizedPath && !this.seenlog.has(<string>ret.normalizedPath)) {
this.backlog.push(<string>ret.normalizedPath); this.backlog.push(<string>ret.normalizedPath);
this.seenlog.add(<string>ret.normalizedPath); this.seenlog.add(<string>ret.normalizedPath);
@ -1884,7 +1971,7 @@ export class Parser extends DiagnosticEmitter {
parseExportImport( parseExportImport(
tn: Tokenizer, tn: Tokenizer,
startRange: Range startPos: i32
): ExportImportStatement | null { ): ExportImportStatement | null {
// at 'export' 'import': Identifier ('=' Identifier)? ';'? // at 'export' 'import': Identifier ('=' Identifier)? ';'?
@ -1894,7 +1981,7 @@ export class Parser extends DiagnosticEmitter {
if (tn.skip(Token.EQUALS)) { if (tn.skip(Token.EQUALS)) {
if (tn.skip(Token.IDENTIFIER)) { if (tn.skip(Token.IDENTIFIER)) {
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let ret = Node.createExportImportStatement(identifier, asIdentifier, Range.join(startRange, tn.range())); let ret = Node.createExportImportStatement(identifier, asIdentifier, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
return ret; return ret;
} else { } else {
@ -1934,9 +2021,7 @@ export class Parser extends DiagnosticEmitter {
break; break;
} }
case Token.CONST: { case Token.CONST: {
statement = this.parseVariable(tn, [ statement = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos);
Node.createModifier(ModifierKind.CONST, tn.range())
], null);
break; break;
} }
case Token.CONTINUE: { case Token.CONTINUE: {
@ -1956,13 +2041,11 @@ export class Parser extends DiagnosticEmitter {
break; break;
} }
case Token.LET: { case Token.LET: {
statement = this.parseVariable(tn, [ statement = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos);
Node.createModifier(ModifierKind.LET, tn.range())
], null);
break; break;
} }
case Token.VAR: { case Token.VAR: {
statement = this.parseVariable(tn, null, null); statement = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos);
break; break;
} }
case Token.OPENBRACE: { case Token.OPENBRACE: {
@ -1995,7 +2078,7 @@ export class Parser extends DiagnosticEmitter {
break; break;
} }
case Token.TYPE: { case Token.TYPE: {
statement = this.parseTypeDeclaration(tn); statement = this.parseTypeDeclaration(tn, CommonFlags.NONE, null, tn.tokenPos);
break; break;
} }
case Token.VOID: { case Token.VOID: {
@ -2142,11 +2225,14 @@ export class Parser extends DiagnosticEmitter {
var startPos = tn.tokenPos; var startPos = tn.tokenPos;
if (tn.skip(Token.OPENPAREN)) { if (tn.skip(Token.OPENPAREN)) {
let initializer: Statement | null = null; let initializer: Statement | null = null;
if (tn.skip(Token.LET) || tn.skip(Token.CONST) || tn.skip(Token.VAR)) { if (tn.skip(Token.CONST)) {
initializer = this.parseVariable(tn, null, null); initializer = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos);
} else if (tn.skip(Token.LET)) {
initializer = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos);
} else if (tn.skip(Token.VAR)) {
initializer = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos);
} else if (!tn.skip(Token.SEMICOLON)) { } else if (!tn.skip(Token.SEMICOLON)) {
initializer = this.parseExpressionStatement(tn); initializer = this.parseExpressionStatement(tn);
@ -2458,21 +2544,20 @@ export class Parser extends DiagnosticEmitter {
parseTypeDeclaration( parseTypeDeclaration(
tn: Tokenizer, tn: Tokenizer,
modifiers: ModifierNode[] | null = null, flags: CommonFlags,
decorators: DecoratorNode[] | null = null decorators: DecoratorNode[] | null,
startPos: i32
): TypeDeclaration | null { ): TypeDeclaration | null {
// at 'type': Identifier ('<' TypeParameters '>')? '=' Type ';'? // at 'type': Identifier ('<' TypeParameters '>')? '=' Type ';'?
var startPos = decorators && decorators.length ? decorators[0].range.start
: modifiers && modifiers.length ? modifiers[0].range.start
: tn.tokenPos;
if (tn.skip(Token.IDENTIFIER)) { if (tn.skip(Token.IDENTIFIER)) {
let name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); let name = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
let typeParameters: TypeParameterNode[] | null = null; let typeParameters: TypeParameterNode[] | null = null;
if (tn.skip(Token.LESSTHAN)) { if (tn.skip(Token.LESSTHAN)) {
typeParameters = this.parseTypeParameters(tn); typeParameters = this.parseTypeParameters(tn);
if (!typeParameters) return null; if (!typeParameters) return null;
flags |= CommonFlags.GENERIC;
} }
if (tn.skip(Token.EQUALS)) { if (tn.skip(Token.EQUALS)) {
let type = this.parseType(tn); let type = this.parseType(tn);
@ -2481,8 +2566,8 @@ export class Parser extends DiagnosticEmitter {
name, name,
typeParameters, typeParameters,
type, type,
modifiers,
decorators, decorators,
flags,
tn.range(startPos, tn.pos) tn.range(startPos, tn.pos)
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);

File diff suppressed because it is too large Load Diff

View File

@ -176,9 +176,7 @@ export enum Token {
ENDOFFILE ENDOFFILE
} }
export namespace Token { export function tokenFomKeyword(text: string): Token {
export function fromKeyword(text: string): Token {
switch (text) { switch (text) {
case "abstract": return Token.ABSTRACT; case "abstract": return Token.ABSTRACT;
case "as": return Token.AS; case "as": return Token.AS;
@ -243,9 +241,9 @@ export namespace Token {
case "yield": return Token.YIELD; case "yield": return Token.YIELD;
default: return Token.INVALID; default: return Token.INVALID;
} }
} }
export function isAlsoIdentifier(token: Token): bool { export function tokenIsAlsoIdentifier(token: Token): bool {
switch (token) { switch (token) {
case Token.ABSTRACT: case Token.ABSTRACT:
case Token.AS: case Token.AS:
@ -263,9 +261,9 @@ export namespace Token {
case Token.TYPE: return true; case Token.TYPE: return true;
default: return false; default: return false;
} }
} }
export function operatorToString(token: Token): string { export function operatorTokenToString(token: Token): string {
switch (token) { switch (token) {
case Token.DELETE: return "delete"; case Token.DELETE: return "delete";
case Token.IN: return "in"; case Token.IN: return "in";
@ -320,7 +318,6 @@ export namespace Token {
return ""; return "";
} }
} }
}
} }
export class Range { export class Range {
@ -356,23 +353,19 @@ export class Range {
get line(): i32 { get line(): i32 {
var text = this.source.text; var text = this.source.text;
var pos = this.start;
var line = 1; var line = 1;
while (pos-- > 0) { for (let pos = this.start; pos >= 0; --pos) {
if (text.charCodeAt(pos) == CharCode.LINEFEED) { if (text.charCodeAt(pos) == CharCode.LINEFEED) line++;
line++;
}
} }
return line; return line;
} }
get column(): i32 { get column(): i32 {
var text = this.source.text; var text = this.source.text;
var pos = this.start;
var column = 0; var column = 0;
while (pos-- > 0) { for (let pos = this.start - 1; pos >= 0; --pos) {
if (text.charCodeAt(pos) == CharCode.LINEFEED) break; if (text.charCodeAt(pos) == CharCode.LINEFEED) break;
column++; ++column;
} }
return column; return column;
} }
@ -396,6 +389,7 @@ export class Tokenizer extends DiagnosticEmitter {
tokenPos: i32 = 0; tokenPos: i32 = 0;
nextToken: Token = -1; nextToken: Token = -1;
nextTokenPos: i32 = 0;
nextTokenOnNewLine: bool = false; nextTokenOnNewLine: bool = false;
constructor(source: Source, diagnostics: DiagnosticMessage[] | null = null) { constructor(source: Source, diagnostics: DiagnosticMessage[] | null = null) {
@ -598,9 +592,12 @@ export class Tokenizer extends DiagnosticEmitter {
// ) { // ) {
// } // }
while (++this.pos < this.end) { while (++this.pos < this.end) {
if (isLineBreak(text.charCodeAt(this.pos))) break; if (isLineBreak(text.charCodeAt(this.pos))) {
++this.pos;
break;
} }
continue; }
break;
} }
if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { // multi-line if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { // multi-line
let closed = false; let closed = false;
@ -622,7 +619,7 @@ export class Tokenizer extends DiagnosticEmitter {
this.range(this.pos), "*/" this.range(this.pos), "*/"
); );
} }
continue; break;
} }
if (text.charCodeAt(this.pos) == CharCode.EQUALS) { if (text.charCodeAt(this.pos) == CharCode.EQUALS) {
++this.pos; ++this.pos;
@ -795,10 +792,10 @@ export class Tokenizer extends DiagnosticEmitter {
} }
} }
let keywordText = text.substring(posBefore, this.pos); let keywordText = text.substring(posBefore, this.pos);
let keywordToken = Token.fromKeyword(keywordText); let keywordToken = tokenFomKeyword(keywordText);
if ( if (
keywordToken != Token.INVALID && keywordToken != Token.INVALID &&
!(preferIdentifier && Token.isAlsoIdentifier(keywordToken)) !(preferIdentifier && tokenIsAlsoIdentifier(keywordToken))
) { ) {
return keywordToken; return keywordToken;
} }
@ -832,6 +829,7 @@ export class Tokenizer extends DiagnosticEmitter {
let tokenBefore = this.token; let tokenBefore = this.token;
let tokenPosBefore = this.tokenPos; let tokenPosBefore = this.tokenPos;
this.nextToken = this.unsafeNext(preferIdentifier, maxCompoundLength); this.nextToken = this.unsafeNext(preferIdentifier, maxCompoundLength);
this.nextTokenPos = this.tokenPos;
if (checkOnNewLine) { if (checkOnNewLine) {
this.nextTokenOnNewLine = false; this.nextTokenOnNewLine = false;
while (--this.tokenPos > posBefore) { while (--this.tokenPos > posBefore) {

View File

@ -100,10 +100,10 @@ export class Type {
return ~0 >>> (targetType.size - this.size); return ~0 >>> (targetType.size - this.size);
} }
/** Tests if this type has the specified capabilities. */ /** Tests if this type has the specified flags. */
is(flags: TypeFlags): bool { is(flags: TypeFlags): bool { return (this.flags & flags) == flags; }
return (this.flags & flags) == flags; /** Tests if this type has any of the specified flags. */
} isAny(flags: TypeFlags): bool { return (this.flags & flags) != 0; }
/** Tests if this type is a class type. */ /** Tests if this type is a class type. */
get isClass(): bool { return this.classType != null; } get isClass(): bool { return this.classType != null; }

18
src/util/text.ts Normal file
View File

@ -0,0 +1,18 @@
const indentX1 = " ";
const indentX2 = " ";
const indentX4 = " ";
/** Creates an indentation matching the number of specified levels. */
export function indent(sb: string[], level: i32): void {
while (level >= 4) {
sb.push(indentX4);
level -= 4;
}
if (level >= 2) {
sb.push(indentX2);
level -= 2;
}
if (level) {
sb.push(indentX1);
}
}

2
std/portable.d.ts vendored
View File

@ -137,7 +137,7 @@ declare function bswap16<T = i16 | u16 | i32 | u32>(value: T): T;
/** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/ /** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/
declare function changetype<T>(value: any): T; declare function changetype<T>(value: any): T;
/** Traps if the specified value is not true-ish, otherwise returns the value. */ /** Traps if the specified value is not true-ish, otherwise returns the value. */
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? declare function assert<T>(isTrueish: T | null, message?: string): T;
/** Parses an integer string to a 64-bit float. */ /** Parses an integer string to a 64-bit float. */
declare function parseInt(str: string, radix?: i32): f64; declare function parseInt(str: string, radix?: i32): f64;
/** Parses an integer string to a 32-bit integer. */ /** Parses an integer string to a 32-bit integer. */

View File

@ -427,7 +427,6 @@
(local $6 i32) (local $6 i32)
(local $7 i32) (local $7 i32)
(local $8 i32) (local $8 i32)
(local $9 i32)
(if (if
(i32.eqz (i32.eqz
(i32.ne (i32.ne
@ -493,14 +492,14 @@
) )
) )
(block $break|0 (block $break|0
(set_local $9 (set_local $5
(get_local $7) (get_local $7)
) )
(loop $continue|0 (loop $continue|0
(if (if
(i32.le_s (i32.le_s
(i32.add (i32.add
(get_local $9) (get_local $5)
(get_local $8) (get_local $8)
) )
(get_local $4) (get_local $4)
@ -516,7 +515,7 @@
(i32.const 4) (i32.const 4)
) )
(i32.shl (i32.shl
(get_local $9) (get_local $5)
(i32.const 1) (i32.const 1)
) )
) )
@ -531,13 +530,13 @@
) )
) )
(return (return
(get_local $9) (get_local $5)
) )
) )
) )
(set_local $9 (set_local $5
(i32.add (i32.add
(get_local $9) (get_local $5)
(i32.const 1) (i32.const 1)
) )
) )

View File

@ -21,10 +21,10 @@ glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => {
var failed = false; var failed = false;
var parser = new Parser(); var parser = new Parser();
var sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, ""); var sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n");
parser.parseFile(sourceText, filename, true); parser.parseFile(sourceText, filename, true);
var serializedSourceText = ASTBuilder.build(parser.program.sources[0]); var serializedSourceText = ASTBuilder.build(parser.program.sources[0]);
var actual = serializedSourceText + parser.diagnostics.map(diagnostic => "// " + diagnostic + "\n").join(""); var actual = serializedSourceText + parser.diagnostics.map(diagnostic => "// " + diagnostic +"\n").join("");
var fixture = filename + ".fixture.ts"; var fixture = filename + ".fixture.ts";
if (isCreate) { if (isCreate) {

View File

@ -1,13 +1,27 @@
export class Test<T> { export class Valid<T> {
instanceFunction(): void { constructor() {}
} instanceFunction(): void {}
static staticFunction(): void { static staticFunction(): void {}
} get instanceGetter(): i32 {}
get instanceGetter(): i32 { static set staticSetter(v: i32) {}
return 0;
}
static set staticSetter(v: i32) {
}
instanceField: i32; instanceField: i32;
static staticField: i32; static staticField: i32;
} }
export class Invalid<T> {
// 1092: Type parameters cannot appear on a constructor declaration
constructor<T>() {}
// 1110: Type expected.
instanceFunction() {}
// 1094: An accessor cannot have type parameters.
// 1054: A 'get' accessor cannot have parameters.
// 1110: Type expected.
get instanceGetter<T>(a: i32) {}
// 1094: An accessor cannot have type parameters.
// 1049: A 'set' accessor must have exactly one parameter.
// 1095: A 'set' accessor cannot have a return type annotation.
set instanceSetter<T>(): i32 {}
}

View File

@ -1,13 +1,23 @@
export class Test<T> { export class Valid<T> {
instanceFunction(): void { constructor() {}
instanceFunction(): void {}
static staticFunction(): void {}
get instanceGetter(): i32 {}
static set staticSetter(v: i32) {}
instanceField: i32;
static staticField: i32;
} }
static staticFunction(): void { export class Invalid<T> {
} constructor<T>() {}
get instanceGetter(): i32 { instanceFunction(): {}
return 0; get instanceGetter<T>(a: i32): {}
} set instanceSetter<T>() {}
static set staticSetter(v: i32) {
}
instanceField: i32;
static staticField: i32;
} }
// ERROR 1092: "Type parameters cannot appear on a constructor declaration." in class.ts:13:13
// ERROR 1110: "Type expected." in class.ts:16:20
// ERROR 1094: "An accessor cannot have type parameters." in class.ts:21:20
// ERROR 1054: "A 'get' accessor cannot have parameters." in class.ts:21:6
// ERROR 1110: "Type expected." in class.ts:21:31
// ERROR 1094: "An accessor cannot have type parameters." in class.ts:26:20
// ERROR 1049: "A 'set' accessor must have exactly one parameter." in class.ts:26:6
// ERROR 1095: "A 'set' accessor cannot have a return type annotation." in class.ts:26:25

View File

@ -1,4 +1,7 @@
var; while for let; a from "./other"; // 1003: Identifier expected.
var;
// 1005: '(' expected.
while for let; a from "./other";
do { do {
; ;
} while (false); } while (false);

View File

@ -3,7 +3,7 @@ a;
from; from;
"./other"; "./other";
do { do {
; ;
} while (false); } while (false);
// ERROR 1003: "Identifier expected." in continue-on-error.ts @ 0,3 // ERROR 1003: "Identifier expected." in continue-on-error.ts:2:0
// ERROR 1005: "'(' expected." in continue-on-error.ts @ 5,10 // ERROR 1005: "'(' expected." in continue-on-error.ts:4:0

View File

@ -1,5 +1,5 @@
do { do {
; ;
} while (a != b); } while (a != b);
do b;
do b; while (a); while (a);

View File

@ -1,5 +1,5 @@
do { do {
; ;
} while (a != b); } while (a != b);
do b; do b;
while (a); while (a);

View File

@ -1,10 +1,10 @@
export const enum A { export const enum A {
B = 1, B = 1,
C, C,
D = 3 D = 3
} }
enum E { enum E {
F, F,
G = 1 + 2, G = 1 + 2,
H = 3 * 4 H = 3 * 4
} }

View File

@ -1,9 +1,9 @@
for (var i: i32 = 0; i < 10; ++i) { for (var i: i32 = 0; i < 10; ++i) {
; ;
} }
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
; ;
} }
for (;;) { for (;;) {
; ;
} }

View File

@ -1,16 +1,16 @@
var a = function(): void { var a = function(): void {
; ;
}; };
var b = function someName(): void { var b = function someName(): void {
; ;
}; };
var c = function(a: i32, b: i32): i32 { var c = function(a: i32, b: i32): i32 {
; ;
}; };
var d = (): void => { var d = (): void => {
; ;
}; };
var e = (a: i32, b: i32): i32 => { var e = (a: i32, b: i32): i32 => {
; ;
}; };
var f = (a: i32): i32 => a; var f = (a: i32): i32 => a;

View File

@ -1,7 +1,4 @@
function simple(): void { function simple(): void {}
} function typeparams<T, V extends T>(a: V | null = null): void {}
function typeparams<T, V extends T>(a: V | null = null): void {
}
@decorator() @decorator()
function withdecorator(): void { function withdecorator(): void {}
}

View File

@ -1,7 +1,4 @@
function simple(): void { function simple(): void {}
} function typeparams<T, V extends T>(a: V | null = null): void {}
function typeparams<T, V extends T>(a: V | null = null): void {
}
@decorator() @decorator()
function withdecorator(): void { function withdecorator(): void {}
}

View File

@ -1,9 +1,16 @@
import { A } from "./other"; import {
A
import { A, B, C } from "./other"; } from "./other";
import {
import { A as B, C, D as E, F } from "./other"; A,
B,
C
} from "./other";
import {
A as B,
C,
D as E,
F
} from "./other";
import * as A from "./other"; import * as A from "./other";
import "./other"; import "./other";

View File

@ -1,16 +1,16 @@
import { import {
A A
} from "./other"; } from "./other";
import { import {
A, A,
B, B,
C C
} from "./other"; } from "./other";
import { import {
A as B, A as B,
C, C,
D as E, D as E,
F F
} from "./other"; } from "./other";
import * as A from "./other"; import * as A from "./other";
import "./other"; import "./other";

View File

@ -45,7 +45,6 @@
0b0; 0b0;
0b1; 0b1;
0b1111111111111111111111111111111; 0b1111111111111111111111111111111;
"123"; "123";
"1\"23"; "1\"23";
"1\"2\\3"; "1\"2\\3";

View File

@ -1,14 +1,11 @@
declare namespace A { declare namespace A {
namespace B { namespace B {
export namespace C { export namespace C {
var aVar: i32; var aVar: i32;
const aConst: i32 = 0; const aConst: i32 = 0;
function aFunc(): void { function aFunc(): void {}
} enum AnEnum {}
enum AnEnum { class AClass {}
} }
class AClass { }
}
}
}
} }

View File

@ -1,6 +1,11 @@
function restValid(a: i32, ...b: i32[]): void {} function restValid(a: i32, ...b: i32[]): void {}
function optionalValid(a: i32, b?: i32): void {}
// 1014: A rest parameter must be last in a parameter list.
function restParameterMustBeLast(...a: i32[], b: i32): void {} function restParameterMustBeLast(...a: i32[], b: i32): void {}
function optionalValid(a: i32, b?: i32): void {} // 1016: A required parameter cannot follow an optional parameter.
function optionalCannotPrecedeRequired(a?: i32, b: i32): void {} function optionalCannotPrecedeRequired(a?: i32, b: i32): void {}
// 1016: A required parameter cannot follow an optional parameter.
function optionalWithInitializerCannotPrecedeRequired(a: i32 = 1, b: i32): void {} function optionalWithInitializerCannotPrecedeRequired(a: i32 = 1, b: i32): void {}

View File

@ -1,13 +1,8 @@
function restValid(a: i32, ...b: Array<i32>): void { function restValid(a: i32, ...b: Array<i32>): void {}
} function optionalValid(a: i32, b?: i32): void {}
function restParameterMustBeLast(...a: Array<i32>, b: i32): void { function restParameterMustBeLast(...a: Array<i32>, b: i32): void {}
} function optionalCannotPrecedeRequired(a?: i32, b: i32): void {}
function optionalValid(a: i32, b?: i32): void { function optionalWithInitializerCannotPrecedeRequired(a: i32 = 1, b: i32): void {}
} // ERROR 1014: "A rest parameter must be last in a parameter list." in parameter-order.ts:5:36
function optionalCannotPrecedeRequired(a?: i32, b: i32): void { // ERROR 1016: "A required parameter cannot follow an optional parameter." in parameter-order.ts:8:48
} // ERROR 1016: "A required parameter cannot follow an optional parameter." in parameter-order.ts:11:66
function optionalWithInitializerCannotPrecedeRequired(a: i32 = 1, b: i32): void {
}
// ERROR 1014: "A rest parameter must be last in a parameter list." in parameter-order.ts @ 85,86
// ERROR 1016: "A required parameter cannot follow an optional parameter." in parameter-order.ts @ 210,211
// ERROR 1016: "A required parameter cannot follow an optional parameter." in parameter-order.ts @ 293,294

View File

@ -1,30 +1,10 @@
// with modifiers /(abc)\//ig; // with modifiers
/(abc)\//ig; /(abc)\//; // without modifiers
var re = /(abc)\//ig; // can be assigned
// without modifiers var noRe = !/(abc)\//i; // generally behaves like an expression
/(abc)\//;
// can be assigned
var re = /(abc)\//ig;
// generally behaves like an expression
var noRe = !/(abc)\//i;
// inner line break is unterminated
/a /a
b/ig; b/ig; // inner line break is unterminated
// just a comment
//ig; //ig;
/(abc)\//iig; // duplicate flags
// duplicate flags /(abc)\//iX; // invalid flags
false && /abc/gX.test(someString) || true; // surrounding AST remains intact
/(abc)\//iig;
// invalid flags
/(abc)\//iX;
// surrounding AST remains intact
false && /abc/gX.test(someString) || true;

View File

@ -5,8 +5,8 @@ var noRe = !/(abc)\//i;
/(abc)\//iig; /(abc)\//iig;
/(abc)\//iX; /(abc)\//iX;
false && /abc/gX.test(someString) || true; false && /abc/gX.test(someString) || true;
// ERROR 1161: "Unterminated regular expression literal." in regexp.ts @ 75,76 // ERROR 1161: "Unterminated regular expression literal." in regexp.ts:5:1
// ERROR 1005: "'/' expected." in regexp.ts @ 74,76 // ERROR 1005: "'/' expected." in regexp.ts:5:0
// ERROR 209: "Invalid regular expression flags." in regexp.ts @ 95,98 // ERROR 209: "Invalid regular expression flags." in regexp.ts:8:9
// ERROR 209: "Invalid regular expression flags." in regexp.ts @ 111,113 // ERROR 209: "Invalid regular expression flags." in regexp.ts:9:9
// ERROR 209: "Invalid regular expression flags." in regexp.ts @ 131,133 // ERROR 209: "Invalid regular expression flags." in regexp.ts:10:14

View File

@ -1,5 +1,4 @@
// a host-bindings syntax experiment // a host-bindings syntax experiment
@binding(BindingCall.NEW, [ BindingType.STRING ], BindingType.OBJECT_HANDLE) @binding(BindingCall.NEW, [ BindingType.STRING ], BindingType.OBJECT_HANDLE)
export class ExternalString { export class ExternalString {

View File

@ -1,65 +1,65 @@
@binding(BindingCall.NEW, [BindingType.STRING], BindingType.OBJECT_HANDLE) @binding(BindingCall.NEW, [BindingType.STRING], BindingType.OBJECT_HANDLE)
export class ExternalString { export class ExternalString {
@binding(BindingCall.FUNCTION, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE) @binding(BindingCall.FUNCTION, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE)
static fromCharCode(char: u16, schar: u16 = <u16>-1): String { static fromCharCode(char: u16, schar: u16 = <u16>-1): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.FUNCTION, [BindingType.U32], BindingType.OBJECT_HANDLE) @binding(BindingCall.FUNCTION, [BindingType.U32], BindingType.OBJECT_HANDLE)
static fromCodePoint(codepoint: u32): String { static fromCodePoint(codepoint: u32): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.U32], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [BindingType.U32], BindingType.OBJECT_HANDLE)
charAt(index: u32): String { charAt(index: u32): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.U32], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.U32], BindingType.PASS_THRU)
charCodeAt(index: u32): u16 { charCodeAt(index: u32): u16 {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.U32], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.U32], BindingType.PASS_THRU)
codePointAt(index: u32): u32 { codePointAt(index: u32): u32 {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.OBJECT_HANDLE)
@operator("+") @operator("+")
concat(other: String): String { concat(other: String): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU)
endsWith(other: String): bool { endsWith(other: String): bool {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU)
indexOf(other: String): i32 { indexOf(other: String): i32 {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU)
startsWith(other: String): bool { startsWith(other: String): bool {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE)
substr(start: i32, length: i32): String { substr(start: i32, length: i32): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [BindingType.U32, BindingType.U32], BindingType.OBJECT_HANDLE)
substring(start: i32, end: i32): String { substring(start: i32, end: i32): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE)
trim(): String { trim(): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE)
trimLeft(): String { trimLeft(): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE) @binding(BindingCall.THIS, [], BindingType.OBJECT_HANDLE)
trimRight(): String { trimRight(): String {
return unreachable(); return unreachable();
} }
@binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU) @binding(BindingCall.THIS, [BindingType.OBJECT_HANDLE], BindingType.PASS_THRU)
@operator("==") @operator("==")
equals(other: String): bool { equals(other: String): bool {
return unreachable(); return unreachable();
} }
} }

View File

@ -3,5 +3,8 @@ var b: i32;
const c: i32 = 0; const c: i32 = 0;
var d = 2; var d = 2;
var e; // type expected // 1110: Type expected.
const f: i32; // must be initialized var e;
// 1155: 'const' declarations must be initialized.
const f: i32;

View File

@ -4,5 +4,5 @@ const c: i32 = 0;
var d = 2; var d = 2;
var e; var e;
const f: i32; const f: i32;
// ERROR 1110: "Type expected." in var.ts @ 59,59 // ERROR 1110: "Type expected." in var.ts:7:5
// ERROR 1155: "'const' declarations must be initialized." in var.ts @ 84,85 // ERROR 1155: "'const' declarations must be initialized." in var.ts:10:6

View File

@ -1,10 +1,10 @@
while (1) { while (1) {
; ;
} }
while (false) { while (false) {
; ;
} }
while ("str") { while ("str") {
; ;
} }
while (1) ; while (1);

View File

@ -7,24 +7,27 @@ require("../src/glue/js");
const { Tokenizer, Token } = require("../src/tokenizer"); const { Tokenizer, Token } = require("../src/tokenizer");
const { Source, SourceKind } = require("../src/ast"); const { Source, SourceKind } = require("../src/ast");
const text = fs.readFileSync(__dirname + "/../src/tokenizer.ts").toString(); var file = process.argv.length > 2 ? process.argv[2] : path.join(__dirname, "..", "src", "tokenizer.ts");
const text = fs.readFileSync(file).toString();
const tn = new Tokenizer(new Source("compiler.ts", text, SourceKind.ENTRY)); const tn = new Tokenizer(new Source("compiler.ts", text, SourceKind.ENTRY));
do { do {
let token = tn.next(); let token = tn.next();
let range = tn.range();
process.stdout.write(Token[token] + " @ " + range.line + ":" + range.column);
if (token == Token.IDENTIFIER) { if (token == Token.IDENTIFIER) {
console.log(Token[token] + " > " + tn.readIdentifier()); process.stdout.write(" > " + tn.readIdentifier());
} else if (token == Token.INTEGERLITERAL) { } else if (token == Token.INTEGERLITERAL) {
console.log(Token[token] + " > " + tn.readInteger()); process.stdout.write(" > " + tn.readInteger());
} else if (token == Token.FLOATLITERAL) { } else if (token == Token.FLOATLITERAL) {
console.log(Token[token] + " > " + tn.readFloat()); process.stdout.write(" > " + tn.readFloat());
} else if (token == Token.STRINGLITERAL) { } else if (token == Token.STRINGLITERAL) {
console.log(Token[token] + " > " + tn.readString()); process.stdout.write(" > " + tn.readString());
} else if (token == Token.ENDOFFILE) { } else if (token == Token.ENDOFFILE) {
console.log(Token[token]); process.stdout.write("\n");
break; break;
} else { } else {
let range = tn.range(); process.stdout.write(" > " + range.source.text.substring(range.start, range.end));
console.log(Token[token] + " > " + range.source.text.substring(range.start, range.end));
} }
process.stdout.write("\n");
} while (true); } while (true);