mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
Progress; Restructuring
This commit is contained in:
parent
e14d02e040
commit
f55fc70220
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.*
|
npm-debug.*
|
||||||
out/
|
out/
|
||||||
|
raw/
|
||||||
|
|
||||||
|
186
src/ast.ts
186
src/ast.ts
@ -53,6 +53,7 @@
|
|||||||
│ ├ VariableStatement <> VariableDeclaration
|
│ ├ VariableStatement <> VariableDeclaration
|
||||||
│ └ WhileStatement
|
│ └ WhileStatement
|
||||||
├ Parameter
|
├ Parameter
|
||||||
|
├ Source
|
||||||
├ SwitchCase
|
├ SwitchCase
|
||||||
├ TypeNode
|
├ TypeNode
|
||||||
└ TypeParameter
|
└ TypeParameter
|
||||||
@ -65,8 +66,8 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Token, operatorTokenToString, Range } from "./tokenizer";
|
import { Token, Tokenizer, operatorTokenToString, Range } from "./tokenizer";
|
||||||
import { CharCode, I64, sb } from "./util";
|
import { CharCode, I64, normalizePath, resolvePath } from "./util";
|
||||||
|
|
||||||
export { Range } from "./tokenizer";
|
export { Range } from "./tokenizer";
|
||||||
|
|
||||||
@ -106,6 +107,7 @@ export enum NodeKind {
|
|||||||
BREAK,
|
BREAK,
|
||||||
CLASS, // is also declaration
|
CLASS, // is also declaration
|
||||||
CONTINUE,
|
CONTINUE,
|
||||||
|
DECORATOR,
|
||||||
DO,
|
DO,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
ENUM, // is also declaration
|
ENUM, // is also declaration
|
||||||
@ -202,7 +204,7 @@ export class TypeNode extends Node {
|
|||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
if (this.parameters.length) {
|
if (this.parameters.length) {
|
||||||
sb.push("<");
|
sb.push("<");
|
||||||
for (let i: i32 = 0; i < this.parameters.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.parameters.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.parameters[i].serialize(sb);
|
this.parameters[i].serialize(sb);
|
||||||
@ -398,7 +400,7 @@ export class ArrayLiteralExpression extends LiteralExpression {
|
|||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("[");
|
sb.push("[");
|
||||||
for (let i: i32 = 0; i < this.elementExpressions.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.elementExpressions.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
if (this.elementExpressions[i])
|
if (this.elementExpressions[i])
|
||||||
@ -410,7 +412,7 @@ export class ArrayLiteralExpression extends LiteralExpression {
|
|||||||
serializeAsTree(sb: string[], indent: i32 = 0): void {
|
serializeAsTree(sb: string[], indent: i32 = 0): void {
|
||||||
pushIndent(sb, indent++);
|
pushIndent(sb, indent++);
|
||||||
sb.push("[\n");
|
sb.push("[\n");
|
||||||
for (let i: i32 = 0; i < this.elementExpressions.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.elementExpressions.length; i < k; ++i) {
|
||||||
pushIndent(sb, indent);
|
pushIndent(sb, indent);
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(",\n");
|
sb.push(",\n");
|
||||||
@ -499,9 +501,10 @@ export class CallExpression extends Expression {
|
|||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
this.expression.serialize(sb);
|
this.expression.serialize(sb);
|
||||||
|
let i: i32, k: i32;
|
||||||
if (this.typeArguments.length) {
|
if (this.typeArguments.length) {
|
||||||
sb.push("<");
|
sb.push("<");
|
||||||
for (let i: i32 = 0; i < this.typeArguments.length; ++i) {
|
for (i = 0, k = this.typeArguments.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.typeArguments[i].serialize(sb);
|
this.typeArguments[i].serialize(sb);
|
||||||
@ -509,7 +512,7 @@ export class CallExpression extends Expression {
|
|||||||
sb.push(">(");
|
sb.push(">(");
|
||||||
} else
|
} else
|
||||||
sb.push("(");
|
sb.push("(");
|
||||||
for (let i: i32 = 0; i < this.arguments.length; ++i) {
|
for (i = 0, k = this.arguments.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.arguments[i].serialize(sb);
|
this.arguments[i].serialize(sb);
|
||||||
@ -806,7 +809,7 @@ export abstract class Statement extends Node {
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createClass(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], range: Range): ClassDeclaration {
|
static createClass(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], decorators: DecoratorStatement[], range: Range): ClassDeclaration {
|
||||||
const stmt: ClassDeclaration = new ClassDeclaration();
|
const stmt: ClassDeclaration = new ClassDeclaration();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -816,6 +819,7 @@ export abstract class Statement extends Node {
|
|||||||
if (stmt.extendsType = extendsType) (<TypeNode>extendsType).parent = stmt;
|
if (stmt.extendsType = extendsType) (<TypeNode>extendsType).parent = stmt;
|
||||||
for (i = 0, k = (stmt.implementsTypes = implementsTypes).length; i < k; ++i) implementsTypes[i].parent = stmt;
|
for (i = 0, k = (stmt.implementsTypes = implementsTypes).length; i < k; ++i) implementsTypes[i].parent = stmt;
|
||||||
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
|
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
|
||||||
|
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -826,6 +830,14 @@ export abstract class Statement extends Node {
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createDecorator(expression: Expression, args: Expression[], range: Range): DecoratorStatement {
|
||||||
|
const stmt: DecoratorStatement = new DecoratorStatement();
|
||||||
|
stmt.range = range;
|
||||||
|
(stmt.expression = expression).parent = stmt;
|
||||||
|
for (let i: i32 = 0, k: i32 = (stmt.arguments = args).length; i < k; ++i) args[i].parent = stmt;
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
static createDo(statement: Statement, condition: Expression, range: Range): DoStatement {
|
static createDo(statement: Statement, condition: Expression, range: Range): DoStatement {
|
||||||
const stmt: DoStatement = new DoStatement();
|
const stmt: DoStatement = new DoStatement();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
@ -865,6 +877,7 @@ export abstract class Statement extends Node {
|
|||||||
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
|
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
|
||||||
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
|
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
|
||||||
stmt.path = path;
|
stmt.path = path;
|
||||||
|
stmt.normalizedPath = path == null ? null : resolvePath(normalizePath(<string>path), range.source.normalizedPath);
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,6 +918,7 @@ export abstract class Statement extends Node {
|
|||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
for (let i: i32 = 0, k: i32 = (stmt.declarations = declarations).length; i < k; ++i) declarations[i].parent = stmt;
|
for (let i: i32 = 0, k: i32 = (stmt.declarations = declarations).length; i < k; ++i) declarations[i].parent = stmt;
|
||||||
stmt.path = path;
|
stmt.path = path;
|
||||||
|
stmt.normalizedPath = resolvePath(normalizePath(path), range.source.normalizedPath);
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,7 +940,7 @@ export abstract class Statement extends Node {
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createField(modifiers: Modifier[], identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, range: Range): FieldDeclaration {
|
static createField(modifiers: Modifier[], identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, decorators: DecoratorStatement[], range: Range): FieldDeclaration {
|
||||||
const stmt: FieldDeclaration = new FieldDeclaration();
|
const stmt: FieldDeclaration = new FieldDeclaration();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -934,6 +948,7 @@ export abstract class Statement extends Node {
|
|||||||
(stmt.identifier = identifier).parent = stmt;
|
(stmt.identifier = identifier).parent = stmt;
|
||||||
if (stmt.type = type) (<TypeNode>type).parent = stmt;
|
if (stmt.type = type) (<TypeNode>type).parent = stmt;
|
||||||
if (stmt.initializer = initializer) (<Expression>initializer).parent = stmt;
|
if (stmt.initializer = initializer) (<Expression>initializer).parent = stmt;
|
||||||
|
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,7 +980,7 @@ export abstract class Statement extends Node {
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createFunction(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, range: Range): FunctionDeclaration {
|
static createFunction(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, decorators: DecoratorStatement[], range: Range): FunctionDeclaration {
|
||||||
const stmt: FunctionDeclaration = new FunctionDeclaration();
|
const stmt: FunctionDeclaration = new FunctionDeclaration();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -975,10 +990,11 @@ export abstract class Statement extends Node {
|
|||||||
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
|
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
|
||||||
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;
|
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;
|
||||||
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
|
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
|
||||||
|
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createMethod(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, range: Range): MethodDeclaration {
|
static createMethod(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, decorators: DecoratorStatement[], range: Range): MethodDeclaration {
|
||||||
const stmt: MethodDeclaration = new MethodDeclaration();
|
const stmt: MethodDeclaration = new MethodDeclaration();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -988,6 +1004,7 @@ export abstract class Statement extends Node {
|
|||||||
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
|
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
|
||||||
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;;
|
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;;
|
||||||
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
|
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
|
||||||
|
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1053,7 +1070,7 @@ export abstract class Statement extends Node {
|
|||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
|
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
|
||||||
for (i = 0, k = (stmt.members = declarations).length; i < k; ++i) declarations[i].parent = stmt;
|
for (i = 0, k = (stmt.declarations = declarations).length; i < k; ++i) declarations[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,13 +1092,30 @@ export abstract class Statement extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class SourceNode extends Node { // extended by Source
|
export class Source extends Node {
|
||||||
|
|
||||||
kind = NodeKind.SOURCE;
|
kind = NodeKind.SOURCE;
|
||||||
parent = null;
|
parent = null;
|
||||||
path: string;
|
path: string;
|
||||||
|
normalizedPath: string;
|
||||||
statements: Statement[];
|
statements: Statement[];
|
||||||
|
|
||||||
|
text: string;
|
||||||
|
tokenizer: Tokenizer | null = null;
|
||||||
|
isEntry: bool;
|
||||||
|
|
||||||
|
constructor(path: string, text: string, isEntry: bool) {
|
||||||
|
super();
|
||||||
|
this.path = path;
|
||||||
|
this.normalizedPath = normalizePath(path, true);
|
||||||
|
this.statements = new Array();
|
||||||
|
this.range = new Range(this, 0, text.length);
|
||||||
|
this.text = text;
|
||||||
|
this.isEntry = isEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDeclaration(): bool { return !this.isEntry && this.path.endsWith(".d.ts"); }
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0, k = this.statements.length; i < k; ++i) {
|
for (let i: i32 = 0, k = this.statements.length; i < k; ++i) {
|
||||||
const statement: Statement = this.statements[i];
|
const statement: Statement = this.statements[i];
|
||||||
@ -1097,7 +1131,6 @@ export abstract class SourceNode extends Node { // extended by Source
|
|||||||
|
|
||||||
export abstract class DeclarationStatement extends Statement {
|
export abstract class DeclarationStatement extends Statement {
|
||||||
identifier: IdentifierExpression;
|
identifier: IdentifierExpression;
|
||||||
reflectionIndex: i32 = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BlockStatement extends Statement {
|
export class BlockStatement extends Statement {
|
||||||
@ -1107,9 +1140,9 @@ export class BlockStatement extends Statement {
|
|||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("{\n");
|
sb.push("{\n");
|
||||||
for (let i: i32 = 0; i < this.statements.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) {
|
||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1140,9 +1173,15 @@ export class ClassDeclaration extends DeclarationStatement {
|
|||||||
extendsType: TypeNode | null;
|
extendsType: TypeNode | null;
|
||||||
implementsTypes: TypeNode[];
|
implementsTypes: TypeNode[];
|
||||||
members: DeclarationStatement[];
|
members: DeclarationStatement[];
|
||||||
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
|
this.decorators[i].serialize(sb);
|
||||||
|
sb.push("\n");
|
||||||
|
}
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
@ -1150,7 +1189,7 @@ export class ClassDeclaration extends DeclarationStatement {
|
|||||||
sb.push(this.identifier.name);
|
sb.push(this.identifier.name);
|
||||||
if (this.typeParameters.length) {
|
if (this.typeParameters.length) {
|
||||||
sb.push("<");
|
sb.push("<");
|
||||||
for (let i: i32 = 0; i < this.typeParameters.length; ++i) {
|
for (i = 0, k = this.typeParameters.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.typeParameters[i].serialize(sb);
|
this.typeParameters[i].serialize(sb);
|
||||||
@ -1163,16 +1202,16 @@ export class ClassDeclaration extends DeclarationStatement {
|
|||||||
}
|
}
|
||||||
if (this.implementsTypes.length) {
|
if (this.implementsTypes.length) {
|
||||||
sb.push(" implements ");
|
sb.push(" implements ");
|
||||||
for (let i: i32 = 0; i < this.implementsTypes.length; ++i) {
|
for (i = 0, k = this.implementsTypes.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.implementsTypes[i].serialize(sb);
|
this.implementsTypes[i].serialize(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1195,6 +1234,25 @@ export class ContinueStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DecoratorStatement extends Statement {
|
||||||
|
|
||||||
|
kind = NodeKind.DECORATOR;
|
||||||
|
expression: Expression;
|
||||||
|
arguments: Expression[];
|
||||||
|
|
||||||
|
serialize(sb: string[]): void {
|
||||||
|
sb.push("@");
|
||||||
|
this.expression.serialize(sb);
|
||||||
|
sb.push("(");
|
||||||
|
for (let i: i32 = 0, k: i32 = this.arguments.length; i < k; ++i) {
|
||||||
|
if (i > 0)
|
||||||
|
sb.push(", ");
|
||||||
|
this.arguments[i].serialize(sb);
|
||||||
|
}
|
||||||
|
sb.push(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DoStatement extends Statement {
|
export class DoStatement extends Statement {
|
||||||
|
|
||||||
kind = NodeKind.DO;
|
kind = NodeKind.DO;
|
||||||
@ -1227,14 +1285,15 @@ export class EnumDeclaration extends DeclarationStatement {
|
|||||||
members: EnumValueDeclaration[];
|
members: EnumValueDeclaration[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
sb.push("enum ");
|
sb.push("enum ");
|
||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(",\n");
|
sb.push(",\n");
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
@ -1292,14 +1351,16 @@ export class ExportStatement extends Statement {
|
|||||||
modifiers: Modifier[];
|
modifiers: Modifier[];
|
||||||
members: ExportMember[];
|
members: ExportMember[];
|
||||||
path: string | null;
|
path: string | null;
|
||||||
|
normalizedPath: string | null;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
sb.push("export {\n");
|
sb.push("export {\n");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(",\n");
|
sb.push(",\n");
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
@ -1329,9 +1390,15 @@ export class FieldDeclaration extends DeclarationStatement {
|
|||||||
modifiers: Modifier[];
|
modifiers: Modifier[];
|
||||||
type: TypeNode | null;
|
type: TypeNode | null;
|
||||||
initializer: Expression | null;
|
initializer: Expression | null;
|
||||||
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
|
this.decorators[i].serialize(sb);
|
||||||
|
sb.push("\n");
|
||||||
|
}
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
@ -1382,9 +1449,15 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
parameters: Parameter[];
|
parameters: Parameter[];
|
||||||
returnType: TypeNode | null;
|
returnType: TypeNode | null;
|
||||||
statements: Statement[] | null;
|
statements: Statement[] | null;
|
||||||
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
|
this.decorators[i].serialize(sb);
|
||||||
|
sb.push("\n");
|
||||||
|
}
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
@ -1394,9 +1467,10 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
|
|
||||||
protected serializeCommon(sb: string[]): void {
|
protected serializeCommon(sb: string[]): void {
|
||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
|
let i: i32, k: i32;
|
||||||
if (this.typeParameters.length) {
|
if (this.typeParameters.length) {
|
||||||
sb.push("<");
|
sb.push("<");
|
||||||
for (let i: i32 = 0; i < this.typeParameters.length; ++i) {
|
for (i = 0, k = this.typeParameters.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.typeParameters[i].serialize(sb);
|
this.typeParameters[i].serialize(sb);
|
||||||
@ -1404,7 +1478,7 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
sb.push(">");
|
sb.push(">");
|
||||||
}
|
}
|
||||||
sb.push("(");
|
sb.push("(");
|
||||||
for (let i: i32 = 0; i < this.parameters.length; ++i) {
|
for (i = 0, k = this.parameters.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.parameters[i].serialize(sb);
|
this.parameters[i].serialize(sb);
|
||||||
@ -1416,10 +1490,10 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
sb.push(")");
|
sb.push(")");
|
||||||
if (this.statements) {
|
if (this.statements) {
|
||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (let i: i32 = 0; i < (<Statement[]>this.statements).length; ++i) {
|
for (i = 0, k = (<Statement[]>this.statements).length; i < k; ++i) {
|
||||||
const statement: Statement = (<Statement[]>this.statements)[i];
|
const statement: Statement = (<Statement[]>this.statements)[i];
|
||||||
statement.serialize(sb);
|
statement.serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1472,10 +1546,11 @@ export class ImportStatement extends Statement {
|
|||||||
kind = NodeKind.IMPORT;
|
kind = NodeKind.IMPORT;
|
||||||
declarations: ImportDeclaration[];
|
declarations: ImportDeclaration[];
|
||||||
path: string;
|
path: string;
|
||||||
|
normalizedPath: string;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("import {\n");
|
sb.push("import {\n");
|
||||||
for (let i: i32 = 0; i < this.declarations.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.declarations.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(",\n");
|
sb.push(",\n");
|
||||||
this.declarations[i].serialize(sb);
|
this.declarations[i].serialize(sb);
|
||||||
@ -1494,7 +1569,8 @@ export class InterfaceDeclaration extends DeclarationStatement {
|
|||||||
members: Statement[];
|
members: Statement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
@ -1502,7 +1578,7 @@ export class InterfaceDeclaration extends DeclarationStatement {
|
|||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
if (this.typeParameters.length) {
|
if (this.typeParameters.length) {
|
||||||
sb.push("<");
|
sb.push("<");
|
||||||
for (let i: i32 = 0; i < this.typeParameters.length; ++i) {
|
for (i = 0, k = this.typeParameters.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.typeParameters[i].serialize(sb);
|
this.typeParameters[i].serialize(sb);
|
||||||
@ -1514,9 +1590,9 @@ export class InterfaceDeclaration extends DeclarationStatement {
|
|||||||
(<TypeNode>this.extendsType).serialize(sb);
|
(<TypeNode>this.extendsType).serialize(sb);
|
||||||
}
|
}
|
||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1530,7 +1606,12 @@ export class MethodDeclaration extends FunctionDeclaration {
|
|||||||
kind = NodeKind.METHOD;
|
kind = NodeKind.METHOD;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
|
this.decorators[i].serialize(sb);
|
||||||
|
sb.push("\n");
|
||||||
|
}
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
@ -1545,16 +1626,17 @@ export class NamespaceDeclaration extends DeclarationStatement {
|
|||||||
members: DeclarationStatement[];
|
members: DeclarationStatement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
}
|
}
|
||||||
sb.push("namespace ");
|
sb.push("namespace ");
|
||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1634,11 +1716,11 @@ export class SwitchCase extends Node {
|
|||||||
sb.push(":\n");
|
sb.push(":\n");
|
||||||
} else
|
} else
|
||||||
sb.push("default:\n");
|
sb.push("default:\n");
|
||||||
for (let i: i32 = 0; i < this.statements.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
if (endsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1656,7 +1738,7 @@ export class SwitchStatement extends Statement {
|
|||||||
sb.push("switch (");
|
sb.push("switch (");
|
||||||
this.expression.serialize(sb);
|
this.expression.serialize(sb);
|
||||||
sb.push(") {\n");
|
sb.push(") {\n");
|
||||||
for (let i: i32 = 0; i < this.cases.length; ++i) {
|
for (let i: i32 = 0, k: i32 = this.cases.length; i < k; ++i) {
|
||||||
this.cases[i].serialize(sb);
|
this.cases[i].serialize(sb);
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
}
|
}
|
||||||
@ -1684,14 +1766,15 @@ export class TryStatement extends Statement {
|
|||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("try {\n");
|
sb.push("try {\n");
|
||||||
for (let i: i32 = 0; i < this.statements.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.statements.length; i < k; ++i) {
|
||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
}
|
}
|
||||||
sb.push("} catch (");
|
sb.push("} catch (");
|
||||||
this.catchVariable.serialize(sb);
|
this.catchVariable.serialize(sb);
|
||||||
sb.push(") {\n");
|
sb.push(") {\n");
|
||||||
for (let i: i32 = 0; i < this.catchStatements.length; ++i) {
|
for (i = 0, k = this.catchStatements.length; i < k; ++i) {
|
||||||
this.catchStatements[i].serialize(sb);
|
this.catchStatements[i].serialize(sb);
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
}
|
}
|
||||||
@ -1722,11 +1805,12 @@ export class VariableStatement extends Statement {
|
|||||||
|
|
||||||
kind = NodeKind.VARIABLE;
|
kind = NodeKind.VARIABLE;
|
||||||
modifiers: Modifier[];
|
modifiers: Modifier[];
|
||||||
members: VariableDeclaration[];
|
declarations: VariableDeclaration[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let isConst: bool = false;
|
let isConst: bool = false;
|
||||||
for (let i: i32 = 0; i < this.modifiers.length; ++i) {
|
let i: i32, k: i32;
|
||||||
|
for (i = 0, k = this.modifiers.length; i < k; ++i) {
|
||||||
this.modifiers[i].serialize(sb);
|
this.modifiers[i].serialize(sb);
|
||||||
sb.push(" ");
|
sb.push(" ");
|
||||||
if (this.modifiers[i].modifierKind == ModifierKind.CONST)
|
if (this.modifiers[i].modifierKind == ModifierKind.CONST)
|
||||||
@ -1734,10 +1818,10 @@ export class VariableStatement extends Statement {
|
|||||||
}
|
}
|
||||||
if (!isConst)
|
if (!isConst)
|
||||||
sb.push("let ");
|
sb.push("let ");
|
||||||
for (let i: i32 = 0; i < this.members.length; ++i) {
|
for (i = 0, k = this.declarations.length; i < k; ++i) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push(", ");
|
sb.push(", ");
|
||||||
this.members[i].serialize(sb);
|
this.declarations[i].serialize(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1768,12 +1852,12 @@ export function isDeclarationStatement(kind: NodeKind): bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function serialize(node: Node, indent: i32 = 0): string {
|
export function serialize(node: Node, indent: i32 = 0): string {
|
||||||
sb.length = 0;
|
const sb: string[] = new Array(); // shared builder could grow too much
|
||||||
node.serialize(sb);
|
node.serialize(sb);
|
||||||
return sb.join("");
|
return sb.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function endsWith(code: CharCode, sb: string[]): bool {
|
function builderEndsWith(code: CharCode, sb: string[]): bool {
|
||||||
if (sb.length) {
|
if (sb.length) {
|
||||||
const last: string = sb[sb.length - 1];
|
const last: string = sb[sb.length - 1];
|
||||||
return last.length ? last.charCodeAt(last.length - 1) == code : false;
|
return last.length ? last.charCodeAt(last.length - 1) == code : false;
|
||||||
|
2
src/binaryen.d.ts
vendored
2
src/binaryen.d.ts
vendored
@ -219,7 +219,7 @@ declare type BinaryenExportRef = usize;
|
|||||||
declare function _BinaryenAddExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef;
|
declare function _BinaryenAddExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef;
|
||||||
declare function _BinaryenRemoveExport(module: BinaryenModuleRef, externalName: CString): void;
|
declare function _BinaryenRemoveExport(module: BinaryenModuleRef, externalName: CString): void;
|
||||||
|
|
||||||
declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenImportRef;
|
declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenImportRef; // sic
|
||||||
|
|
||||||
declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, funcs: CArray<BinaryenFunctionRef>, numFuncs: BinaryenIndex): void;
|
declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, funcs: CArray<BinaryenFunctionRef>, numFuncs: BinaryenIndex): void;
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addFunction(name: string, type: Type, varTypes: Type[], body: BinaryenExpressionRef): BinaryenFunctionRef {
|
addFunction(name: string, type: BinaryenFunctionTypeRef, varTypes: Type[], body: BinaryenExpressionRef): BinaryenFunctionRef {
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
const cArr: CArray<i32> = allocI32Array(varTypes);
|
const cArr: CArray<i32> = allocI32Array(varTypes);
|
||||||
try {
|
try {
|
||||||
|
375
src/compiler.ts
375
src/compiler.ts
@ -2,23 +2,28 @@ import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType
|
|||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { hasModifier } from "./parser";
|
import { hasModifier } from "./parser";
|
||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
import { CharCode, I64, U64 } from "./util";
|
import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
||||||
import { Token } from "./tokenizer";
|
import { Token } from "./tokenizer";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
NodeKind,
|
NodeKind,
|
||||||
TypeNode,
|
TypeNode,
|
||||||
|
Source,
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
BlockStatement,
|
BlockStatement,
|
||||||
BreakStatement,
|
BreakStatement,
|
||||||
ClassDeclaration,
|
ClassDeclaration,
|
||||||
ContinueStatement,
|
ContinueStatement,
|
||||||
|
DeclarationStatement,
|
||||||
DoStatement,
|
DoStatement,
|
||||||
EmptyStatement,
|
EmptyStatement,
|
||||||
EnumDeclaration,
|
EnumDeclaration,
|
||||||
EnumValueDeclaration,
|
EnumValueDeclaration,
|
||||||
|
ExportMember,
|
||||||
|
ExportStatement,
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
|
FieldDeclaration,
|
||||||
FunctionDeclaration,
|
FunctionDeclaration,
|
||||||
ForStatement,
|
ForStatement,
|
||||||
IfStatement,
|
IfStatement,
|
||||||
@ -58,19 +63,12 @@ import {
|
|||||||
} from "./ast";
|
} from "./ast";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
Enum,
|
ClassType,
|
||||||
Class,
|
FunctionType,
|
||||||
Field,
|
|
||||||
Function,
|
|
||||||
GlobalVariable,
|
|
||||||
LocalVariable,
|
|
||||||
Namespace,
|
|
||||||
Method,
|
|
||||||
Source,
|
|
||||||
Type,
|
Type,
|
||||||
TypeKind
|
TypeKind
|
||||||
|
|
||||||
} from "./reflection";
|
} from "./types";
|
||||||
|
|
||||||
export enum Target {
|
export enum Target {
|
||||||
WASM32,
|
WASM32,
|
||||||
@ -79,6 +77,7 @@ export enum Target {
|
|||||||
|
|
||||||
export class Options {
|
export class Options {
|
||||||
target: Target = Target.WASM32;
|
target: Target = Target.WASM32;
|
||||||
|
noEmit: bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Compiler extends DiagnosticEmitter {
|
export class Compiler extends DiagnosticEmitter {
|
||||||
@ -87,16 +86,20 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
options: Options;
|
options: Options;
|
||||||
module: Module;
|
module: Module;
|
||||||
|
|
||||||
|
startFunction: FunctionType = new FunctionType(Type.void, new Array());
|
||||||
|
startFunctionBody: BinaryenExpressionRef[] = new Array();
|
||||||
|
|
||||||
currentType: Type = Type.void;
|
currentType: Type = Type.void;
|
||||||
currentClass: Class | null = null;
|
currentClass: ClassType | null = null;
|
||||||
currentFunction: Function | null = null;
|
currentFunction: FunctionType = this.startFunction;
|
||||||
breakMajor: i32 = 0;
|
|
||||||
breakMinor: i32 = 0;
|
|
||||||
|
|
||||||
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
|
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
|
||||||
memorySegments: MemorySegment[] = new Array();
|
memorySegments: MemorySegment[] = new Array();
|
||||||
|
|
||||||
statements: BinaryenExpressionRef[] = new Array(); // TODO: make start function
|
classes: Map<string,ClassType> = new Map();
|
||||||
|
enums: Set<string> = new Set();
|
||||||
|
functions: Map<string,FunctionType> = new Map();
|
||||||
|
globals: Set<string> = new Set();
|
||||||
|
|
||||||
static compile(program: Program, options: Options | null = null): Module {
|
static compile(program: Program, options: Options | null = null): Module {
|
||||||
const compiler: Compiler = new Compiler(program, options);
|
const compiler: Compiler = new Compiler(program, options);
|
||||||
@ -123,62 +126,61 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
switch (statement.kind) {
|
switch (statement.kind) {
|
||||||
|
|
||||||
case NodeKind.CLASS:
|
case NodeKind.CLASS:
|
||||||
if (hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>statement).modifiers) && !(<ClassDeclaration>statement).typeParameters.length) {
|
if (hasModifier(ModifierKind.EXPORT, (<ClassDeclaration>statement).modifiers) && !(<ClassDeclaration>statement).typeParameters.length)
|
||||||
const cl: Class = Class.create(<ClassDeclaration>statement, []).exportAs((<ClassDeclaration>statement).identifier.name);
|
this.compileClass(<ClassDeclaration>statement, []);
|
||||||
this.program.addClass(cl);
|
|
||||||
this.compileClass(cl);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.ENUM:
|
case NodeKind.ENUM:
|
||||||
if (hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>statement).modifiers)) {
|
if (hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>statement).modifiers))
|
||||||
const en: Enum = Enum.create(<EnumDeclaration>statement).exportAs((<EnumDeclaration>statement).identifier.name);
|
this.compileEnum(<EnumDeclaration>statement);
|
||||||
this.program.addEnum(en);
|
|
||||||
this.compileEnum(en);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.FUNCTION:
|
case NodeKind.FUNCTION:
|
||||||
if (hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>statement).modifiers) && !(<FunctionDeclaration>statement).typeParameters.length) {
|
if (hasModifier(ModifierKind.EXPORT, (<FunctionDeclaration>statement).modifiers) && !(<FunctionDeclaration>statement).typeParameters.length)
|
||||||
const fn: Function = Function.create(<FunctionDeclaration>statement, []).exportAs((<FunctionDeclaration>statement).identifier.name);
|
this.compileFunction(<FunctionDeclaration>statement, []);
|
||||||
this.program.addFunction(fn);
|
|
||||||
this.compileFunction(fn);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.IMPORT:
|
case NodeKind.IMPORT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.NAMESPACE:
|
case NodeKind.NAMESPACE:
|
||||||
if (hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>statement).modifiers)) {
|
if (hasModifier(ModifierKind.EXPORT, (<NamespaceDeclaration>statement).modifiers))
|
||||||
const ns: Namespace = Namespace.create(<NamespaceDeclaration>statement).exportAs((<NamespaceDeclaration>statement).identifier.name);
|
this.compileNamespace(<NamespaceDeclaration>statement);
|
||||||
this.program.addNamespace(ns);
|
|
||||||
this.compileNamespace(ns);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.VARIABLE:
|
case NodeKind.VARIABLE:
|
||||||
if (hasModifier(ModifierKind.EXPORT, (<VariableStatement>statement).modifiers)) {
|
if (hasModifier(ModifierKind.EXPORT, (<VariableStatement>statement).modifiers))
|
||||||
const gls: GlobalVariable[] = GlobalVariable.create(<VariableStatement>statement);
|
this.compileGlobals(<VariableStatement>statement);
|
||||||
for (let j: i32 = 0, l: i32 = gls.length; j < l; ++j) {
|
|
||||||
const gl: GlobalVariable = gls[j];
|
|
||||||
gl.exportName = (<VariableDeclaration>gl.declaration).identifier.name; // WASM can't do this right now
|
|
||||||
this.program.addGlobal(gl);
|
|
||||||
this.compileGlobal(gl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.EXPORT:
|
case NodeKind.EXPORT: {
|
||||||
// TODO: obtain referenced declaration and export that
|
this.compileExports(<ExportStatement>statement);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
this.statements.push(this.compileStatement(statement));
|
const previousClass: ClassType | null = this.currentClass;
|
||||||
|
const previousFunction: FunctionType = this.currentFunction;
|
||||||
|
this.currentClass = null;
|
||||||
|
this.currentFunction = this.startFunction;
|
||||||
|
this.startFunctionBody.push(this.compileStatement(statement));
|
||||||
|
this.currentClass = previousClass;
|
||||||
|
this.currentFunction = previousFunction;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make start function if not empty
|
||||||
|
if (this.startFunctionBody.length) {
|
||||||
|
let typeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(BinaryenType.None, []);
|
||||||
|
if (!typeRef)
|
||||||
|
typeRef = this.module.addFunctionType("v", BinaryenType.None, []);
|
||||||
|
this.module.setStart(
|
||||||
|
this.module.addFunction(".start", typeRef, [], this.module.createBlock("", this.startFunctionBody))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// set up memory size and static segments
|
// set up memory size and static segments
|
||||||
const initial: U64 = this.memoryOffset.clone();
|
const initial: U64 = this.memoryOffset.clone();
|
||||||
const initialOverlaps: U64 = initial.clone();
|
const initialOverlaps: U64 = initial.clone();
|
||||||
@ -193,34 +195,115 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return this.module;
|
return this.module;
|
||||||
}
|
}
|
||||||
|
|
||||||
compileClass(cl: Class): void {
|
compileClass(declaration: ClassDeclaration, typeArguments: Type[]): void {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
compileEnum(en: Enum): void {
|
compileEnum(declaration: EnumDeclaration): void {
|
||||||
for (let i: i32 = 0, k = en.declaration.members.length; i < k; ++i) {
|
const name: string = this.program.mangleInternalName(declaration);
|
||||||
const declaration: EnumValueDeclaration = en.declaration.members[i];
|
if (this.enums.has(name)) {
|
||||||
const name: string = this.program.mangleName(declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||||
const value: BinaryenExpressionRef = declaration.value
|
return;
|
||||||
? this.compileExpression(<Expression>declaration.value, Type.i32)
|
|
||||||
: this.module.createI32(i); // TODO
|
|
||||||
this.module.addGlobal(name, BinaryenType.I32, false, value);
|
|
||||||
if (en.exportName != null) {
|
|
||||||
// TODO: WASM does not yet support non-function exports
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const valueDeclarations: EnumValueDeclaration[] = declaration.members;
|
||||||
|
let previousValueName: string | null = null;
|
||||||
|
for (let i: i32 = 0, k: i32 = valueDeclarations.length; i < k; ++i)
|
||||||
|
previousValueName = this.compileEnumValue(valueDeclarations[i], previousValueName);
|
||||||
|
this.enums.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileFunction(fn: Function): void {
|
compileEnumValue(declaration: EnumValueDeclaration, previousName: string | null): string {
|
||||||
|
const name: string = this.program.mangleInternalName(declaration);
|
||||||
|
let initializer: BinaryenExpressionRef = declaration.value ? this.compileExpression(<Expression>declaration.value, Type.i32) : 0;
|
||||||
|
if (!this.options.noEmit) {
|
||||||
|
if (!initializer) initializer = previousName == null
|
||||||
|
? this.module.createI32(0)
|
||||||
|
: this.module.createBinary(BinaryOp.AddI32,
|
||||||
|
this.module.createGetGlobal(previousName, BinaryenType.I32),
|
||||||
|
this.module.createI32(1)
|
||||||
|
);
|
||||||
|
this.module.addGlobal(name, BinaryenType.I32, false, initializer);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
compileFunction(declaration: FunctionDeclaration, typeArguments: Type[]): void {
|
||||||
|
/* const binaryenResultType: BinaryenType = declaration.returnType ? this.resolveType(<TypeNode>declaration.returnType, true) : BinaryenType.None;
|
||||||
|
const binaryenParamTypes: BinaryenType[] = new Array();
|
||||||
|
let binaryenTypeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
|
||||||
|
if (!binaryenTypeRef)
|
||||||
|
binaryenTypeRef = this.module.addFunctionType("", binaryenResultType, binaryenParamTypes); */
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
compileGlobal(gl: GlobalVariable): void {
|
compileGlobals(statement: VariableStatement): void {
|
||||||
|
const declarations: VariableDeclaration[] = statement.declarations;
|
||||||
|
const isConst: bool = hasModifier(ModifierKind.CONST, statement.modifiers);
|
||||||
|
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i)
|
||||||
|
this.compileGlobal(declarations[i], isConst);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileGlobal(declaration: VariableDeclaration, isConst: bool): void {
|
||||||
|
const type: Type | null = declaration.type ? this.resolveType(<TypeNode>declaration.type) : null; // reports
|
||||||
|
if (!type)
|
||||||
|
return;
|
||||||
|
const name: string = this.program.mangleInternalName(declaration);
|
||||||
|
if (this.globals.has(name)) {
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.options.noEmit) {
|
||||||
|
const binaryenType: BinaryenType = typeToBinaryenType(<Type>type);
|
||||||
|
const initializer: BinaryenExpressionRef = declaration.initializer ? this.compileExpression(<Expression>declaration.initializer, <Type>type) : typeToBinaryenZero(this.module, <Type>type);
|
||||||
|
this.module.addGlobal(name, binaryenType, !isConst, initializer);
|
||||||
|
}
|
||||||
|
this.globals.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileNamespace(declaration: NamespaceDeclaration): void {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
compileNamespace(ns: Namespace): void {
|
compileExports(statement: ExportStatement): void {
|
||||||
throw new Error("not implemented");
|
const members: ExportMember[] = statement.members;
|
||||||
|
const normalizedPath: string | null = statement.path == null ? null : normalizePath(<string>statement.path);
|
||||||
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
||||||
|
this.compileExport(members[i], normalizedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileExport(member: ExportMember, normalizedPath: string | null): void {
|
||||||
|
const exportName: string = normalizedPath + "/" + member.externalIdentifier.name;
|
||||||
|
const declaration: DeclarationStatement | null = <DeclarationStatement | null>this.program.exports.get(exportName);
|
||||||
|
if (declaration) {
|
||||||
|
switch ((<DeclarationStatement>declaration).kind) {
|
||||||
|
|
||||||
|
case NodeKind.CLASS:
|
||||||
|
if (!(<ClassDeclaration>declaration).typeParameters.length)
|
||||||
|
this.compileClass(<ClassDeclaration>declaration, []);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.ENUM:
|
||||||
|
this.compileEnum(<EnumDeclaration>declaration);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.FUNCTION:
|
||||||
|
if (!(<FunctionDeclaration>declaration).typeParameters.length)
|
||||||
|
this.compileFunction(<FunctionDeclaration>declaration, []);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.NAMESPACE:
|
||||||
|
this.compileNamespace(<NamespaceDeclaration>declaration);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.VARIABLEDECLARATION:
|
||||||
|
this.compileGlobal(<VariableDeclaration>declaration, hasModifier(ModifierKind.CONST, (<VariableStatement>declaration.parent).modifiers));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error("unexpected declaration kind");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
throw new Error("unexpected missing declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory
|
// memory
|
||||||
@ -238,31 +321,23 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
resolveType(node: TypeNode, reportNotFound: bool = true): Type | null {
|
resolveType(node: TypeNode, typeArgumentsMap: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
||||||
|
// TODO: resolve node and its arguments using typeArgumentsMap
|
||||||
|
// TODO: make types for classes in program.ts
|
||||||
const types: Map<string,Type> = this.program.types;
|
const types: Map<string,Type> = this.program.types;
|
||||||
const name: string = node.identifier.name;
|
const globalName: string = node.identifier.name;
|
||||||
if (types.has(name)) {
|
const localName: string = node.range.source.normalizedPath + "/" + globalName;
|
||||||
const type: Type = <Type>types.get(name);
|
if (types.has(localName))
|
||||||
return type;
|
return <Type>types.get(localName);
|
||||||
}
|
if (types.has(globalName))
|
||||||
|
return <Type>types.get(globalName);
|
||||||
if (reportNotFound)
|
if (reportNotFound)
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, name);
|
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
|
|
||||||
enterBreakContext(): string {
|
|
||||||
if (this.breakMinor == 0)
|
|
||||||
++this.breakMajor;
|
|
||||||
++this.breakMinor;
|
|
||||||
return this.breakMajor.toString() + "." + this.breakMinor.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
leaveBreakContext(): void {
|
|
||||||
--this.breakMinor;
|
|
||||||
}
|
|
||||||
|
|
||||||
compileStatement(statement: Statement): BinaryenExpressionRef {
|
compileStatement(statement: Statement): BinaryenExpressionRef {
|
||||||
switch (statement.kind) {
|
switch (statement.kind) {
|
||||||
|
|
||||||
@ -355,7 +430,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
compileReturnStatement(statement: ReturnStatement): BinaryenExpressionRef {
|
compileReturnStatement(statement: ReturnStatement): BinaryenExpressionRef {
|
||||||
if (this.currentFunction) {
|
if (this.currentFunction) {
|
||||||
const expression: BinaryenExpressionRef = statement.expression ? this.compileExpression(<Expression>statement.expression, (<Function>this.currentFunction).returnType) : 0;
|
const expression: BinaryenExpressionRef = statement.expression ? this.compileExpression(<Expression>statement.expression, this.currentFunction.returnType) : 0;
|
||||||
return this.module.createReturn(expression);
|
return this.module.createReturn(expression);
|
||||||
}
|
}
|
||||||
return this.module.createUnreachable();
|
return this.module.createUnreachable();
|
||||||
@ -379,11 +454,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
compileWhileStatement(statement: WhileStatement): BinaryenExpressionRef {
|
compileWhileStatement(statement: WhileStatement): BinaryenExpressionRef {
|
||||||
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
|
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
|
||||||
const label: string = this.enterBreakContext();
|
const label: string = this.currentFunction.enterBreakContext();
|
||||||
const breakLabel: string = "break$" + label;
|
const breakLabel: string = "break$" + label;
|
||||||
const continueLabel: string = "continue$" + label;
|
const continueLabel: string = "continue$" + label;
|
||||||
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
|
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
|
||||||
this.leaveBreakContext();
|
this.currentFunction.leaveBreakContext();
|
||||||
return this.module.createBlock(breakLabel, [
|
return this.module.createBlock(breakLabel, [
|
||||||
this.module.createLoop(continueLabel,
|
this.module.createLoop(continueLabel,
|
||||||
this.module.createIf(condition, this.module.createBlock("", [
|
this.module.createIf(condition, this.module.createBlock("", [
|
||||||
@ -616,7 +691,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): BinaryenExpressionRef {
|
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
const toType: Type | null = this.resolveType(expression.toType); // reports
|
const toType: Type | null = this.resolveType(expression.toType, this.currentFunction.typeArgumentsMap); // reports
|
||||||
if (toType && toType != contextualType) {
|
if (toType && toType != contextualType) {
|
||||||
const expr: BinaryenExpressionRef = this.compileExpression(expression.expression, <Type>toType);
|
const expr: BinaryenExpressionRef = this.compileExpression(expression.expression, <Type>toType);
|
||||||
return this.convertExpression(expr, this.currentType, <Type>toType);
|
return this.convertExpression(expr, this.currentType, <Type>toType);
|
||||||
@ -835,11 +910,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return compound
|
return compound
|
||||||
? this.compileAssignment(expression.left, this.module.createBinary(op, left, right))
|
? this.compileAssignment(expression.left, this.module.createBinary(op, left, right), this.currentType != Type.void)
|
||||||
: this.module.createBinary(op, left, right);
|
: this.module.createBinary(op, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileAssignment(expression: Expression, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
compileAssignment(expression: Expression, value: BinaryenExpressionRef, tee: bool = false): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,18 +983,37 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): BinaryenExpressionRef {
|
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
let operand: BinaryenExpressionRef;
|
const operator: Token = expression.operator;
|
||||||
let op: UnaryOp;
|
|
||||||
|
|
||||||
switch (expression.operator) {
|
let op: BinaryOp;
|
||||||
|
let binaryenType: BinaryenType;
|
||||||
|
let binaryenOne: BinaryenExpressionRef;
|
||||||
|
|
||||||
case Token.PLUS_PLUS:
|
if (contextualType == Type.f32) {
|
||||||
case Token.MINUS_MINUS:
|
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32;
|
||||||
|
binaryenType = BinaryenType.F32;
|
||||||
default:
|
binaryenOne = this.module.createF32(1);
|
||||||
throw new Error("not implemented");
|
} else if (contextualType == Type.f64) {
|
||||||
|
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64;
|
||||||
|
binaryenType = BinaryenType.F64;
|
||||||
|
binaryenOne = this.module.createF64(1);
|
||||||
|
} else if (contextualType.isLongInteger) {
|
||||||
|
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64;
|
||||||
|
binaryenType = BinaryenType.I64;
|
||||||
|
binaryenOne = this.module.createI64(1, 0);
|
||||||
|
} else {
|
||||||
|
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI32 : BinaryOp.SubI32;
|
||||||
|
binaryenType = BinaryenType.I32;
|
||||||
|
binaryenOne = this.module.createI32(1);
|
||||||
}
|
}
|
||||||
// return this.module.createBinary(op, operand);
|
|
||||||
|
const getValue: BinaryenExpressionRef = this.compileExpression(expression.expression, contextualType);
|
||||||
|
const setValue: BinaryenExpressionRef = this.compileAssignment(expression.expression, this.module.createBinary(op, getValue, binaryenOne), false); // reports
|
||||||
|
|
||||||
|
return this.module.createBlock(null, [
|
||||||
|
getValue,
|
||||||
|
setValue
|
||||||
|
], binaryenType);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef {
|
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
@ -929,7 +1023,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
switch (expression.operator) {
|
switch (expression.operator) {
|
||||||
|
|
||||||
case Token.PLUS:
|
case Token.PLUS:
|
||||||
return this.compileExpression(expression.expression, contextualType);
|
return this.compileExpression(expression.expression, contextualType); // noop
|
||||||
|
|
||||||
case Token.MINUS:
|
case Token.MINUS:
|
||||||
operand = this.compileExpression(expression.expression, contextualType);
|
operand = this.compileExpression(expression.expression, contextualType);
|
||||||
@ -939,12 +1033,29 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
op = UnaryOp.NegF64;
|
op = UnaryOp.NegF64;
|
||||||
else
|
else
|
||||||
return this.currentType.isLongInteger
|
return this.currentType.isLongInteger
|
||||||
? this.module.createBinary(BinaryOp.SubI64, this.module.createI64(0, 0), operand)
|
? this.module.createBinary(BinaryOp.SubI64, this.module.createI64(0, 0), operand)
|
||||||
: this.module.createBinary(BinaryOp.SubI32, this.module.createI32(0), operand);
|
: this.module.createBinary(BinaryOp.SubI32, this.module.createI32(0), operand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case Token.PLUS_PLUS:
|
case Token.PLUS_PLUS:
|
||||||
// case Token.MINUS_MINUS:
|
operand = this.compileExpression(expression.expression, contextualType);
|
||||||
|
return this.currentType == Type.f32
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
||||||
|
: this.currentType == Type.f64
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
||||||
|
: this.currentType.isLongInteger
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
||||||
|
: this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
||||||
|
|
||||||
|
case Token.MINUS_MINUS:
|
||||||
|
operand = this.compileExpression(expression.expression, contextualType);
|
||||||
|
return this.currentType == Type.f32
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
||||||
|
: this.currentType == Type.f64
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
||||||
|
: this.currentType.isLongInteger
|
||||||
|
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
||||||
|
: this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
||||||
|
|
||||||
case Token.EXCLAMATION:
|
case Token.EXCLAMATION:
|
||||||
operand = this.compileExpression(expression.expression, Type.bool, false);
|
operand = this.compileExpression(expression.expression, Type.bool, false);
|
||||||
@ -965,8 +1076,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
case Token.TILDE:
|
case Token.TILDE:
|
||||||
operand = this.compileExpression(expression.expression, contextualType.isAnyFloat ? Type.i64 : contextualType);
|
operand = this.compileExpression(expression.expression, contextualType.isAnyFloat ? Type.i64 : contextualType);
|
||||||
return this.currentType.isLongInteger
|
return this.currentType.isLongInteger
|
||||||
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
|
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
|
||||||
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));
|
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
@ -975,3 +1086,57 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return this.module.createUnary(op, operand);
|
return this.module.createUnary(op, operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
function typeToBinaryenType(type: Type): BinaryenType {
|
||||||
|
return type.kind == TypeKind.F32
|
||||||
|
? BinaryenType.F32
|
||||||
|
: type.kind == TypeKind.F64
|
||||||
|
? BinaryenType.F64
|
||||||
|
: type.isLongInteger
|
||||||
|
? BinaryenType.I64
|
||||||
|
: type.isAnyInteger || type.kind == TypeKind.BOOL
|
||||||
|
? BinaryenType.I32
|
||||||
|
: BinaryenType.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
|
||||||
|
return type.kind == TypeKind.F32
|
||||||
|
? module.createF32(0)
|
||||||
|
: type.kind == TypeKind.F64
|
||||||
|
? module.createF64(0)
|
||||||
|
: type.isLongInteger
|
||||||
|
? module.createI64(0, 0)
|
||||||
|
: module.createI32(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeToBinaryenOne(module: Module, type: Type): BinaryenExpressionRef {
|
||||||
|
return type.kind == TypeKind.F32
|
||||||
|
? module.createF32(1)
|
||||||
|
: type.kind == TypeKind.F64
|
||||||
|
? module.createF64(1)
|
||||||
|
: type.isLongInteger
|
||||||
|
? module.createI64(1, 0)
|
||||||
|
: module.createI32(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeToSignatureNamePart(type: Type): string {
|
||||||
|
return type.kind == TypeKind.VOID
|
||||||
|
? "v"
|
||||||
|
: type.kind == TypeKind.F32
|
||||||
|
? "f"
|
||||||
|
: type.kind == TypeKind.F64
|
||||||
|
? "F"
|
||||||
|
: type.isLongInteger
|
||||||
|
? "I"
|
||||||
|
: "i";
|
||||||
|
}
|
||||||
|
|
||||||
|
function typesToSignatureName(paramTypes: Type[], returnType: Type): string {
|
||||||
|
sb.length = 0;
|
||||||
|
for (let i: i32 = 0, k = paramTypes.length; i < k; ++i)
|
||||||
|
sb.push(typeToSignatureNamePart(paramTypes[i]));
|
||||||
|
sb.push(typeToSignatureNamePart(returnType));
|
||||||
|
return sb.join("");
|
||||||
|
}
|
||||||
|
@ -39,12 +39,14 @@ export enum DiagnosticCode {
|
|||||||
An_implementation_cannot_be_declared_in_ambient_contexts = 1183,
|
An_implementation_cannot_be_declared_in_ambient_contexts = 1183,
|
||||||
An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive = 1198,
|
An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive = 1198,
|
||||||
Unterminated_Unicode_escape_sequence = 1199,
|
Unterminated_Unicode_escape_sequence = 1199,
|
||||||
|
Decorators_are_not_valid_here = 1206,
|
||||||
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
|
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
|
||||||
Duplicate_identifier_0 = 2300,
|
Duplicate_identifier_0 = 2300,
|
||||||
Cannot_find_name_0 = 2304,
|
Cannot_find_name_0 = 2304,
|
||||||
Generic_type_0_requires_1_type_argument_s = 2314,
|
Generic_type_0_requires_1_type_argument_s = 2314,
|
||||||
Type_0_is_not_generic = 2315,
|
Type_0_is_not_generic = 2315,
|
||||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||||
|
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
||||||
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391
|
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,12 +90,14 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 1183: return "An implementation cannot be declared in ambient contexts.";
|
case 1183: return "An implementation cannot be declared in ambient contexts.";
|
||||||
case 1198: return "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.";
|
case 1198: return "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.";
|
||||||
case 1199: return "Unterminated Unicode escape sequence.";
|
case 1199: return "Unterminated Unicode escape sequence.";
|
||||||
|
case 1206: return "Decorators are not valid here.";
|
||||||
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
|
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
|
||||||
case 2300: return "Duplicate identifier '{0}'.";
|
case 2300: return "Duplicate identifier '{0}'.";
|
||||||
case 2304: return "Cannot find name '{0}'.";
|
case 2304: return "Cannot find name '{0}'.";
|
||||||
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
||||||
case 2315: return "Type '{0}' is not generic.";
|
case 2315: return "Type '{0}' is not generic.";
|
||||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||||
|
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
||||||
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"An implementation cannot be declared in ambient contexts.": 1183,
|
"An implementation cannot be declared in ambient contexts.": 1183,
|
||||||
"An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.": 1198,
|
"An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.": 1198,
|
||||||
"Unterminated Unicode escape sequence.": 1199,
|
"Unterminated Unicode escape sequence.": 1199,
|
||||||
|
"Decorators are not valid here.": 1206,
|
||||||
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
|
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
|
||||||
|
|
||||||
"Duplicate identifier '{0}'.": 2300,
|
"Duplicate identifier '{0}'.": 2300,
|
||||||
@ -45,5 +46,6 @@
|
|||||||
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
||||||
"Type '{0}' is not generic.": 2315,
|
"Type '{0}' is not generic.": 2315,
|
||||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||||
|
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
||||||
"Function implementation is missing or not immediately following the declaration.": 2391
|
"Function implementation is missing or not immediately following the declaration.": 2391
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Range } from "./ast";
|
import { Range } from "./ast";
|
||||||
import { CharCode, isLineBreak, sb } from "./util";
|
import { isLineBreak, sb } from "./util";
|
||||||
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||||
|
|
||||||
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import { Module } from "./binaryen";
|
import { Module } from "./binaryen";
|
||||||
import { Compiler } from "./compiler";
|
import { Compiler } from "./compiler";
|
||||||
import { DiagnosticMessage, DiagnosticCategory, DiagnosticCode } from "./diagnostics";
|
import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics";
|
||||||
import { Parser } from "./parser";
|
import { Parser } from "./parser";
|
||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
|
|
||||||
|
126
src/parser.ts
126
src/parser.ts
@ -8,30 +8,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
import { Source } from "./reflection";
|
|
||||||
import { Tokenizer, Token, Range } from "./tokenizer";
|
import { Tokenizer, Token, Range } from "./tokenizer";
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { I64, normalizePath, resolvePath } from "./util";
|
import { normalizePath } from "./util";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
NodeKind,
|
NodeKind,
|
||||||
|
Source,
|
||||||
|
|
||||||
// types
|
// types
|
||||||
TypeNode,
|
TypeNode,
|
||||||
|
|
||||||
// expressions
|
// expressions
|
||||||
AssertionExpression,
|
|
||||||
AssertionKind,
|
AssertionKind,
|
||||||
Expression,
|
Expression,
|
||||||
FloatLiteralExpression,
|
|
||||||
IdentifierExpression,
|
IdentifierExpression,
|
||||||
IntegerLiteralExpression,
|
|
||||||
LiteralExpression,
|
|
||||||
LiteralKind,
|
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
BlockStatement,
|
BlockStatement,
|
||||||
ClassDeclaration,
|
ClassDeclaration,
|
||||||
|
DecoratorStatement,
|
||||||
DoStatement,
|
DoStatement,
|
||||||
EnumDeclaration,
|
EnumDeclaration,
|
||||||
EnumValueDeclaration,
|
EnumValueDeclaration,
|
||||||
@ -79,9 +75,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = this.program.sources.length; i < k; ++i)
|
||||||
if (this.program.sources[i].normalizedPath == normalizedPath)
|
if (this.program.sources[i].normalizedPath == normalizedPath)
|
||||||
throw Error("duplicate source");
|
throw Error("duplicate source");
|
||||||
|
this.seenlog.add(normalizedPath);
|
||||||
if (isEntry)
|
|
||||||
this.seenlog.add(normalizedPath);
|
|
||||||
|
|
||||||
const source: Source = new Source(path, text, isEntry);
|
const source: Source = new Source(path, text, isEntry);
|
||||||
this.program.sources.push(source);
|
this.program.sources.push(source);
|
||||||
@ -91,6 +85,17 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
while (!tn.skip(Token.ENDOFFILE)) {
|
while (!tn.skip(Token.ENDOFFILE)) {
|
||||||
|
|
||||||
|
let decorators: DecoratorStatement[] | null = null;
|
||||||
|
|
||||||
|
while (tn.skip(Token.AT)) {
|
||||||
|
const decorator: DecoratorStatement | null = this.parseDecorator(tn);
|
||||||
|
if (!decorator)
|
||||||
|
break;
|
||||||
|
if (!decorators)
|
||||||
|
decorators = new Array();
|
||||||
|
(<DecoratorStatement[]>decorators).push(<DecoratorStatement>decorator);
|
||||||
|
}
|
||||||
|
|
||||||
let modifiers: Modifier[] | null = null;
|
let modifiers: Modifier[] | null = null;
|
||||||
|
|
||||||
if (tn.skip(Token.EXPORT))
|
if (tn.skip(Token.EXPORT))
|
||||||
@ -127,7 +132,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.FUNCTION:
|
case Token.FUNCTION:
|
||||||
statement = this.parseFunction(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
|
statement = this.parseFunction(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators);
|
||||||
|
decorators = null;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.ABSTRACT:
|
case Token.ABSTRACT:
|
||||||
@ -139,7 +145,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
// fall through
|
// fall through
|
||||||
|
|
||||||
case Token.CLASS:
|
case Token.CLASS:
|
||||||
statement = this.parseClass(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
|
statement = this.parseClass(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators);
|
||||||
|
decorators = null;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.IMPORT:
|
case Token.IMPORT:
|
||||||
@ -170,6 +177,9 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decorators)
|
||||||
|
for (let i: i32 = 0, k: i32 = (<DecoratorStatement[]>decorators).length; i < k; ++i)
|
||||||
|
this.error(DiagnosticCode.Decorators_are_not_valid_here, (<DecoratorStatement[]>decorators)[i].range);
|
||||||
if (!statement)
|
if (!statement)
|
||||||
return;
|
return;
|
||||||
statement.parent = source;
|
statement.parent = source;
|
||||||
@ -270,12 +280,12 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
// ... [][]
|
// ... [][]
|
||||||
while (tn.skip(Token.OPENBRACKET)) {
|
while (tn.skip(Token.OPENBRACKET)) {
|
||||||
let bracketRange: Range = tn.range();
|
let bracketStart: i32 = tn.tokenPos;
|
||||||
if (!tn.skip(Token.CLOSEBRACKET)) {
|
if (!tn.skip(Token.CLOSEBRACKET)) {
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "]");
|
this.error(DiagnosticCode._0_expected, tn.range(), "]");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
bracketRange = Range.join(bracketRange, tn.range());
|
const bracketRange = tn.range(bracketStart, tn.pos);
|
||||||
|
|
||||||
// ...[] | null
|
// ...[] | null
|
||||||
let nullable: bool = false;
|
let nullable: bool = false;
|
||||||
@ -297,6 +307,32 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// statements
|
// statements
|
||||||
|
|
||||||
|
parseDecorator(tn: Tokenizer): DecoratorStatement | null {
|
||||||
|
// at '@': Identifier ('.' Identifier)* '(' Arguments
|
||||||
|
const startPos: i32 = tn.tokenPos;
|
||||||
|
if (tn.skip(Token.IDENTIFIER)) {
|
||||||
|
let name: string = tn.readIdentifier();
|
||||||
|
let expression: Expression = Expression.createIdentifier(name, tn.range(startPos, tn.pos));
|
||||||
|
while (tn.skip(Token.DOT)) {
|
||||||
|
if (tn.skip(Token.IDENTIFIER)) {
|
||||||
|
name = tn.readIdentifier();
|
||||||
|
expression = Expression.createPropertyAccess(expression, Expression.createIdentifier(name, tn.range()), tn.range(startPos, tn.pos));
|
||||||
|
} else {
|
||||||
|
this.error(DiagnosticCode.Identifier_expected, tn.range());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tn.skip(Token.OPENPAREN)) {
|
||||||
|
const args: Expression[] | null = this.parseArguments(tn);
|
||||||
|
if (args)
|
||||||
|
return Statement.createDecorator(expression, <Expression[]>args, tn.range(startPos, tn.pos));
|
||||||
|
} else
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), "(");
|
||||||
|
} else
|
||||||
|
this.error(DiagnosticCode.Identifier_expected, tn.range());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
parseVariable(tn: Tokenizer, modifiers: Modifier[]): VariableStatement | null {
|
parseVariable(tn: Tokenizer, modifiers: Modifier[]): VariableStatement | null {
|
||||||
// at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'?
|
// at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'?
|
||||||
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
|
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
|
||||||
@ -481,9 +517,14 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseFunction(tn: Tokenizer, modifiers: Modifier[]): FunctionDeclaration | null {
|
parseFunction(tn: Tokenizer, modifiers: Modifier[], decorators: DecoratorStatement[] | null): FunctionDeclaration | null {
|
||||||
// at 'function': Identifier ('<' TypeParameters)? '(' Parameters (':' Type)? '{' Statement* '}' ';'?
|
// at 'function': Identifier ('<' TypeParameters)? '(' Parameters (':' Type)? '{' Statement* '}' ';'?
|
||||||
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
|
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length
|
||||||
|
? (<DecoratorStatement[]>decorators)[0].range.start
|
||||||
|
: modifiers.length
|
||||||
|
? modifiers[0].range.start
|
||||||
|
: tn.tokenPos;
|
||||||
|
|
||||||
if (!tn.skip(Token.IDENTIFIER)) {
|
if (!tn.skip(Token.IDENTIFIER)) {
|
||||||
this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos));
|
this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos));
|
||||||
return null;
|
return null;
|
||||||
@ -524,14 +565,18 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
} else if (!isDeclare)
|
} else if (!isDeclare)
|
||||||
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range(tn.pos));
|
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range(tn.pos));
|
||||||
const ret: FunctionDeclaration = Statement.createFunction(modifiers, identifier, typeParameters, <Parameter[]>parameters, returnType, statements, tn.range(startPos, tn.pos));
|
const ret: FunctionDeclaration = Statement.createFunction(modifiers, identifier, typeParameters, <Parameter[]>parameters, returnType, statements, decorators ? <DecoratorStatement[]>decorators : new Array(0), tn.range(startPos, tn.pos));
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseClass(tn: Tokenizer, modifiers: Modifier[]): ClassDeclaration | null {
|
parseClass(tn: Tokenizer, modifiers: Modifier[], decorators: DecoratorStatement[] | null): ClassDeclaration | null {
|
||||||
// at 'class': Identifier ('<' TypeParameters)? ('extends' Type)? ('implements' Type (',' Type)*)? '{' ClassMember* '}'
|
// at 'class': Identifier ('<' TypeParameters)? ('extends' Type)? ('implements' Type (',' Type)*)? '{' ClassMember* '}'
|
||||||
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
|
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length
|
||||||
|
? (<DecoratorStatement[]>decorators)[0].range.start
|
||||||
|
: modifiers.length
|
||||||
|
? modifiers[0].range.start
|
||||||
|
: tn.tokenPos;
|
||||||
|
|
||||||
if (tn.skip(Token.IDENTIFIER)) {
|
if (tn.skip(Token.IDENTIFIER)) {
|
||||||
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
||||||
@ -572,7 +617,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
members.push(<DeclarationStatement>member);
|
members.push(<DeclarationStatement>member);
|
||||||
} while (!tn.skip(Token.CLOSEBRACE));
|
} while (!tn.skip(Token.CLOSEBRACE));
|
||||||
}
|
}
|
||||||
return Statement.createClass(modifiers, identifier, <TypeParameter[]>typeParameters, extendsType, implementsTypes, members, tn.range(startPos, tn.pos));
|
return Statement.createClass(modifiers, identifier, <TypeParameter[]>typeParameters, extendsType, implementsTypes, members, decorators ? <DecoratorStatement[]>decorators : new Array(0), tn.range(startPos, tn.pos));
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
||||||
} else
|
} else
|
||||||
@ -584,6 +629,15 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
// ('public' | 'private' | 'protected')? ('static' | 'abstract')? ('get' | 'set')? Identifier ...
|
// ('public' | 'private' | 'protected')? ('static' | 'abstract')? ('get' | 'set')? Identifier ...
|
||||||
const startRange: Range = tn.range();
|
const startRange: Range = tn.range();
|
||||||
|
|
||||||
|
let decorators: DecoratorStatement[] = new Array();
|
||||||
|
|
||||||
|
while (tn.skip(Token.AT)) {
|
||||||
|
const decorator: DecoratorStatement | null = this.parseDecorator(tn);
|
||||||
|
if (!decorator)
|
||||||
|
break;
|
||||||
|
decorators.push(<DecoratorStatement>decorator);
|
||||||
|
}
|
||||||
|
|
||||||
let modifiers: Modifier[] | null = null;
|
let modifiers: Modifier[] | null = null;
|
||||||
|
|
||||||
if (tn.skip(Token.PUBLIC))
|
if (tn.skip(Token.PUBLIC))
|
||||||
@ -641,7 +695,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range()); // recoverable
|
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range()); // recoverable
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret: MethodDeclaration = Statement.createMethod(modifiers ? modifiers : createModifiers(), identifier, <TypeParameter[]>typeParameters, <Parameter[]>parameters, returnType, statements, Range.join(startRange, tn.range()));
|
const ret: MethodDeclaration = Statement.createMethod(modifiers ? modifiers : createModifiers(), identifier, <TypeParameter[]>typeParameters, <Parameter[]>parameters, returnType, statements, decorators, Range.join(startRange, tn.range()));
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -666,7 +720,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
if (!initializer)
|
if (!initializer)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const ret: FieldDeclaration = Statement.createField(modifiers ? modifiers : createModifiers(), identifier, type, initializer, Range.join(startRange, tn.range()));
|
const ret: FieldDeclaration = Statement.createField(modifiers ? modifiers : createModifiers(), identifier, type, initializer, decorators, Range.join(startRange, tn.range()));
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -694,19 +748,18 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
let path: string | null = null;
|
let path: string | null = null;
|
||||||
if (tn.skip(Token.FROM)) {
|
if (tn.skip(Token.FROM)) {
|
||||||
if (tn.skip(Token.STRINGLITERAL)) {
|
if (tn.skip(Token.STRINGLITERAL))
|
||||||
path = tn.readString();
|
path = tn.readString();
|
||||||
const resolvedPath: string = resolvePath(normalizePath(path), tn.source.normalizedPath);
|
else {
|
||||||
if (!this.seenlog.has(resolvedPath)) {
|
|
||||||
this.backlog.push(resolvedPath);
|
|
||||||
this.seenlog.add(resolvedPath);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.error(DiagnosticCode.String_literal_expected, tn.range());
|
this.error(DiagnosticCode.String_literal_expected, tn.range());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ret: ExportStatement = Statement.createExport(modifiers, members, path, Range.join(startRange, tn.range()));
|
const ret: ExportStatement = Statement.createExport(modifiers, members, path, Range.join(startRange, tn.range()));
|
||||||
|
if (ret.normalizedPath && !this.seenlog.has(<string>ret.normalizedPath)) {
|
||||||
|
this.backlog.push(<string>ret.normalizedPath);
|
||||||
|
this.seenlog.add(<string>ret.normalizedPath);
|
||||||
|
}
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
} else
|
} else
|
||||||
@ -753,12 +806,11 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
if (tn.skip(Token.FROM)) {
|
if (tn.skip(Token.FROM)) {
|
||||||
if (tn.skip(Token.STRINGLITERAL)) {
|
if (tn.skip(Token.STRINGLITERAL)) {
|
||||||
const path: string = tn.readString();
|
const path: string = tn.readString();
|
||||||
const resolvedPath: string = resolvePath(normalizePath(path), tn.source.normalizedPath);
|
|
||||||
if (!this.seenlog.has(resolvedPath)) {
|
|
||||||
this.backlog.push(resolvedPath);
|
|
||||||
this.seenlog.add(resolvedPath);
|
|
||||||
}
|
|
||||||
const ret: ImportStatement = Statement.createImport(members, path, Range.join(startRange, tn.range()));
|
const ret: ImportStatement = Statement.createImport(members, path, Range.join(startRange, tn.range()));
|
||||||
|
if (!this.seenlog.has(ret.normalizedPath)) {
|
||||||
|
this.backlog.push(ret.normalizedPath);
|
||||||
|
this.seenlog.add(ret.normalizedPath);
|
||||||
|
}
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
} else
|
} else
|
||||||
@ -1153,6 +1205,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnaryPrefixExpression
|
// UnaryPrefixExpression
|
||||||
|
if ((<Expression>operand).kind != NodeKind.IDENTIFIER && (<Expression>operand).kind != NodeKind.ELEMENTACCESS && (<Expression>operand).kind != NodeKind.PROPERTYACCESS)
|
||||||
|
this.error(DiagnosticCode.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, (<Expression>operand).range);
|
||||||
return Expression.createUnaryPrefix(token, <Expression>operand, tn.range(startPos, tn.pos));
|
return Expression.createUnaryPrefix(token, <Expression>operand, tn.range(startPos, tn.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1320,6 +1374,8 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// UnaryPostfixExpression
|
// UnaryPostfixExpression
|
||||||
} else if (token == Token.PLUS_PLUS || token == Token.MINUS_MINUS) {
|
} else if (token == Token.PLUS_PLUS || token == Token.MINUS_MINUS) {
|
||||||
|
if (expr.kind != NodeKind.IDENTIFIER && expr.kind != NodeKind.ELEMENTACCESS && expr.kind != NodeKind.PROPERTYACCESS)
|
||||||
|
this.error(DiagnosticCode.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, expr.range);
|
||||||
expr = Expression.createUnaryPostfix(token, expr, tn.range(startPos, tn.pos));
|
expr = Expression.createUnaryPostfix(token, expr, tn.range(startPos, tn.pos));
|
||||||
|
|
||||||
// SelectExpression
|
// SelectExpression
|
||||||
|
256
src/program.ts
256
src/program.ts
@ -1,15 +1,13 @@
|
|||||||
import { Target } from "./compiler";
|
import { Target } from "./compiler";
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { Source, Type, Class, Enum, Function, GlobalVariable, Namespace } from "./reflection";
|
|
||||||
import { hasModifier } from "./parser";
|
import { hasModifier } from "./parser";
|
||||||
import { normalizePath, resolvePath, trimExtension } from "./util";
|
import { Type } from "./types";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
|
ModifierKind,
|
||||||
Node,
|
Node,
|
||||||
NodeKind,
|
NodeKind,
|
||||||
SourceNode,
|
Source,
|
||||||
ModifierKind,
|
|
||||||
IdentifierExpression,
|
|
||||||
|
|
||||||
ClassDeclaration,
|
ClassDeclaration,
|
||||||
DeclarationStatement,
|
DeclarationStatement,
|
||||||
@ -36,7 +34,7 @@ class QueuedExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class QueuedImport {
|
class QueuedImport {
|
||||||
globalName: string;
|
internalName: string;
|
||||||
importName: string;
|
importName: string;
|
||||||
declaration: ImportDeclaration;
|
declaration: ImportDeclaration;
|
||||||
}
|
}
|
||||||
@ -47,20 +45,13 @@ export class Program extends DiagnosticEmitter {
|
|||||||
diagnosticsOffset: i32 = 0;
|
diagnosticsOffset: i32 = 0;
|
||||||
target: Target = Target.WASM32;
|
target: Target = Target.WASM32;
|
||||||
|
|
||||||
// internal names to declarations
|
/** Internal map of names to declarations. */
|
||||||
names: Map<string,DeclarationStatement> = new Map();
|
names: Map<string,DeclarationStatement> = new Map();
|
||||||
// type names to types
|
/** Separate map of internal type names to declarations. */
|
||||||
types: Map<string,Type> = new Map();
|
types: Map<string,Type> = new Map();
|
||||||
// export names to declarations (separate from internal names)
|
/** Separate map of internal export names to declarations. */
|
||||||
exports: Map<string,DeclarationStatement> = new Map();
|
exports: Map<string,DeclarationStatement> = new Map();
|
||||||
|
|
||||||
// reflection instances
|
|
||||||
classes: Class[] = new Array();
|
|
||||||
enums: Enum[] = new Array();
|
|
||||||
functions: Function[] = new Array();
|
|
||||||
globals: GlobalVariable[] = new Array();
|
|
||||||
namespaces: Namespace[] = new Array();
|
|
||||||
|
|
||||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||||
super(diagnostics);
|
super(diagnostics);
|
||||||
this.sources = new Array();
|
this.sources = new Array();
|
||||||
@ -68,12 +59,13 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
initialize(target: Target): void {
|
initialize(target: Target): void {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
|
||||||
initializeBasicTypes(this.types, target);
|
initializeBasicTypes(this.types, target);
|
||||||
|
|
||||||
const exportsMap: Map<string,QueuedExport> = new Map();
|
const queuedExports: Map<string,QueuedExport> = new Map();
|
||||||
const importsQueue: QueuedImport[] = new Array();
|
const queuedImports: QueuedImport[] = new Array();
|
||||||
|
|
||||||
// build initial lookup maps of global and export names to declarations
|
// build initial lookup maps of internal and export names to declarations
|
||||||
for (let i: i32 = 0, k: i32 = this.sources.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = this.sources.length; i < k; ++i) {
|
||||||
const source: Source = this.sources[i];
|
const source: Source = this.sources[i];
|
||||||
const statements: Statement[] = source.statements;
|
const statements: Statement[] = source.statements;
|
||||||
@ -90,7 +82,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.EXPORT:
|
case NodeKind.EXPORT:
|
||||||
this.initializeExports(<ExportStatement>statement, exportsMap);
|
this.initializeExports(<ExportStatement>statement, queuedExports);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.FUNCTION:
|
case NodeKind.FUNCTION:
|
||||||
@ -98,7 +90,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.IMPORT:
|
case NodeKind.IMPORT:
|
||||||
this.initializeImports(<ImportStatement>statement, exportsMap, importsQueue);
|
this.initializeImports(<ImportStatement>statement, queuedExports, queuedImports);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.INTERFACE:
|
case NodeKind.INTERFACE:
|
||||||
@ -116,52 +108,53 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point exports map should be resolvable
|
// at this point queued exports should be resolvable
|
||||||
for (let [key, val] of exportsMap.entries()) {
|
for (let [exportName, queuedExport] of queuedExports.entries()) {
|
||||||
const seen: Set<QueuedExport> = new Set();
|
const seen: Set<QueuedExport> = new Set();
|
||||||
while (exportsMap.has(val.importName)) {
|
while (queuedExports.has(queuedExport.importName)) {
|
||||||
val = <QueuedExport>exportsMap.get(val.importName);
|
queuedExport = <QueuedExport>queuedExports.get(queuedExport.importName);
|
||||||
if (seen.has(val))
|
if (seen.has(queuedExport))
|
||||||
break;
|
break;
|
||||||
seen.add(val);
|
seen.add(queuedExport);
|
||||||
}
|
}
|
||||||
if (this.exports.has(val.importName))
|
if (this.exports.has(queuedExport.importName))
|
||||||
this.addExport(key, <DeclarationStatement>this.exports.get(val.importName));
|
this.addExport(exportName, <DeclarationStatement>this.exports.get(queuedExport.importName));
|
||||||
else
|
else
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, val.member.externalIdentifier.range, val.importName);
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.importName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point imports queue should be resolvable
|
// at this point also queued imports should be resolvable
|
||||||
for (let i: i32 = 0, k: i32 = importsQueue.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = queuedImports.length; i < k; ++i) {
|
||||||
const queued: QueuedImport = importsQueue[i];
|
const queuedImport: QueuedImport = queuedImports[i];
|
||||||
const globalName: string = queued.globalName;
|
const internalName: string = queuedImport.internalName;
|
||||||
let importName: string = queued.importName;
|
let importName: string = queuedImport.importName;
|
||||||
const seen: Set<QueuedExport> = new Set();
|
const seen: Set<QueuedExport> = new Set();
|
||||||
while (exportsMap.has(importName)) {
|
while (queuedExports.has(importName)) {
|
||||||
const val: QueuedExport = <QueuedExport>exportsMap.get(importName);
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(importName);
|
||||||
importName = val.importName;
|
importName = queuedExport.importName;
|
||||||
if (seen.has(val))
|
if (seen.has(queuedExport))
|
||||||
break;
|
break;
|
||||||
seen.add(val);
|
seen.add(queuedExport);
|
||||||
}
|
}
|
||||||
if (this.exports.has(importName)) {
|
if (this.exports.has(importName)) {
|
||||||
if (this.names.has(globalName))
|
if (this.names.has(internalName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, queued.declaration.identifier.range, globalName);
|
this.error(DiagnosticCode.Duplicate_identifier_0, queuedImport.declaration.identifier.range, internalName);
|
||||||
else {
|
else {
|
||||||
const declaration: DeclarationStatement = <DeclarationStatement>this.exports.get(importName);
|
const declaration: DeclarationStatement = <DeclarationStatement>this.exports.get(importName);
|
||||||
this.names.set(globalName, declaration);
|
this.names.set(internalName, declaration);
|
||||||
// TODO: also mirror (non-private) member names?
|
// TODO: also mirror (non-private) member names?
|
||||||
|
// wouldn't it be better to look up members based on their parent?
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queued.declaration.externalIdentifier.range, importName);
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedImport.declaration.externalIdentifier.range, importName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeClass(declaration: ClassDeclaration): void {
|
private initializeClass(declaration: ClassDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
const members: DeclarationStatement[] = declaration.members;
|
const members: DeclarationStatement[] = declaration.members;
|
||||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
||||||
const statement: Statement = members[j];
|
const statement: Statement = members[j];
|
||||||
@ -182,87 +175,91 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeField(declaration: FieldDeclaration): void {
|
private initializeField(declaration: FieldDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeEnum(declaration: EnumDeclaration): void {
|
private initializeEnum(declaration: EnumDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
const members: EnumValueDeclaration[] = declaration.members;
|
const members: EnumValueDeclaration[] = declaration.members;
|
||||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
||||||
this.initializeEnumValue(members[i]);
|
this.initializeEnumValue(members[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeEnumValue(declaration: EnumValueDeclaration): void {
|
private initializeEnumValue(declaration: EnumValueDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeExports(statement: ExportStatement, exportsMap: Map<string,QueuedExport>): void {
|
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
||||||
const members: ExportMember[] = statement.members;
|
const members: ExportMember[] = statement.members;
|
||||||
const normalizedPath: string | null = statement.path == null ? null : normalizePath(<string>statement.path);
|
|
||||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
||||||
this.initializeExport(members[i], normalizedPath, exportsMap);
|
this.initializeExport(members[i], statement.normalizedPath, queuedExports);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeExport(member: ExportMember, normalizedPath: string | null, exportsMap: Map<string,QueuedExport>): void {
|
private initializeExport(member: ExportMember, normalizedPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
||||||
const exportName: string = member.range.source.normalizedPath + "/" + member.externalIdentifier.name;
|
const exportName: string = member.range.source.normalizedPath + "/" + member.externalIdentifier.name;
|
||||||
if (exportsMap.has(exportName))
|
if (queuedExports.has(exportName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, member.externalIdentifier.range, exportName);
|
this.error(DiagnosticCode.Duplicate_identifier_0, member.externalIdentifier.range, exportName);
|
||||||
else {
|
else {
|
||||||
const queued: QueuedExport = new QueuedExport();
|
const queuedExport: QueuedExport = new QueuedExport();
|
||||||
queued.importName = normalizedPath == null
|
queuedExport.importName = normalizedPath == null
|
||||||
? member.range.source.normalizedPath + "/" + member.identifier.name // local
|
? member.range.source.normalizedPath + "/" + member.identifier.name // local
|
||||||
: (<string>normalizedPath) + "/" + member.identifier.name; // re-export
|
: (<string>normalizedPath) + "/" + member.identifier.name; // re-export
|
||||||
queued.member = member;
|
queuedExport.member = member;
|
||||||
exportsMap.set(exportName, queued);
|
queuedExports.set(exportName, queuedExport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeFunction(declaration: FunctionDeclaration): void {
|
private initializeFunction(declaration: FunctionDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeImports(statement: ImportStatement, exportsMap: Map<string,QueuedExport>, importsQueue: QueuedImport[]): void {
|
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||||
const members: ImportDeclaration[] = statement.declarations;
|
const members: ImportDeclaration[] = statement.declarations;
|
||||||
const normalizedPath: string = normalizePath(statement.path);
|
|
||||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
||||||
const declaration: ImportDeclaration = members[i];
|
const declaration: ImportDeclaration = members[i];
|
||||||
this.initializeImport(declaration, normalizedPath, exportsMap, importsQueue);
|
this.initializeImport(declaration, statement.normalizedPath, queuedExports, queuedImports);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeImport(declaration: ImportDeclaration, normalizedPath: string, exportsMap: Map<string,QueuedExport>, importsQueue: QueuedImport[]): void {
|
private initializeImport(declaration: ImportDeclaration, normalizedPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||||
const importName: string = normalizedPath + "/" + declaration.externalIdentifier.name;
|
const importName: string = normalizedPath + "/" + declaration.externalIdentifier.name;
|
||||||
let resolvedImportName: string = importName;
|
let resolvedImportName: string = importName;
|
||||||
while (exportsMap.has(resolvedImportName))
|
const seen: Set<QueuedExport> = new Set();
|
||||||
resolvedImportName = (<QueuedExport>exportsMap.get(resolvedImportName)).importName;
|
while (queuedExports.has(resolvedImportName)) {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(resolvedImportName);
|
||||||
|
resolvedImportName = queuedExport.importName;
|
||||||
|
if (seen.has(queuedExport))
|
||||||
|
break;
|
||||||
|
seen.add(queuedExport);
|
||||||
|
}
|
||||||
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
||||||
if (this.names.has(globalName))
|
if (this.names.has(internalName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, globalName);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
else
|
else
|
||||||
this.names.set(globalName, <DeclarationStatement>this.exports.get(resolvedImportName));
|
this.names.set(internalName, <DeclarationStatement>this.exports.get(resolvedImportName));
|
||||||
} else { // points to yet unresolved export
|
} else { // points to yet unresolved export
|
||||||
const queued: QueuedImport = new QueuedImport();
|
const queuedImport: QueuedImport = new QueuedImport();
|
||||||
queued.globalName = globalName;
|
queuedImport.internalName = internalName;
|
||||||
queued.importName = importName;
|
queuedImport.importName = importName;
|
||||||
queued.declaration = declaration;
|
queuedImport.declaration = declaration;
|
||||||
importsQueue.push(queued);
|
queuedImports.push(queuedImport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeInterface(declaration: InterfaceDeclaration): void {
|
private initializeInterface(declaration: InterfaceDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
const members: Statement[] = declaration.members;
|
const members: Statement[] = declaration.members;
|
||||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
||||||
const statement: Statement = members[j];
|
const statement: Statement = members[j];
|
||||||
@ -283,15 +280,15 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeMethod(declaration: MethodDeclaration): void {
|
private initializeMethod(declaration: MethodDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
const members: Statement[] = declaration.members;
|
const members: Statement[] = declaration.members;
|
||||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
||||||
const statement: Statement = members[j];
|
const statement: Statement = members[j];
|
||||||
@ -327,33 +324,33 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeVariables(statement: VariableStatement, insideNamespace: bool = false): void {
|
private initializeVariables(statement: VariableStatement, isNamespaceMember: bool = false): void {
|
||||||
const declarations: VariableDeclaration[] = statement.members;
|
const declarations: VariableDeclaration[] = statement.declarations;
|
||||||
const isExport: bool = !insideNamespace && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
const isExport: bool = !isNamespaceMember && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
||||||
for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
|
for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
|
||||||
const declaration: VariableDeclaration = declarations[i];
|
const declaration: VariableDeclaration = declarations[i];
|
||||||
const globalName: string = this.mangleName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(globalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
if (isExport)
|
if (isExport)
|
||||||
this.addExport(globalName, declaration);
|
this.addExport(/* same as */internalName, declaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addName(globalName: string, declaration: DeclarationStatement): void {
|
private addName(internalName: string, declaration: DeclarationStatement): void {
|
||||||
if (this.names.has(globalName))
|
if (this.names.has(internalName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, globalName); // recoverable
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); // recoverable
|
||||||
else
|
else
|
||||||
this.names.set(globalName, declaration);
|
this.names.set(internalName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addExport(globalName: string, declaration: DeclarationStatement): void {
|
private addExport(exportName: string, declaration: DeclarationStatement): void {
|
||||||
if (this.exports.has(globalName))
|
if (this.exports.has(exportName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, globalName); // recoverable
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, exportName); // recoverable
|
||||||
else
|
else
|
||||||
this.exports.set(globalName, declaration);
|
this.exports.set(exportName, declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
mangleName(declaration: DeclarationStatement): string {
|
mangleInternalName(declaration: DeclarationStatement): string {
|
||||||
let name: string = declaration.identifier.name;
|
let name: string = declaration.identifier.name;
|
||||||
let parent: Node | null = declaration.parent;
|
let parent: Node | null = declaration.parent;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@ -367,28 +364,28 @@ export class Program extends DiagnosticEmitter {
|
|||||||
(declaration.kind == NodeKind.FIELD && !hasModifier(ModifierKind.STATIC, (<FieldDeclaration>declaration).modifiers)) ||
|
(declaration.kind == NodeKind.FIELD && !hasModifier(ModifierKind.STATIC, (<FieldDeclaration>declaration).modifiers)) ||
|
||||||
(declaration.kind == NodeKind.METHOD && !hasModifier(ModifierKind.STATIC, (<MethodDeclaration>declaration).modifiers))
|
(declaration.kind == NodeKind.METHOD && !hasModifier(ModifierKind.STATIC, (<MethodDeclaration>declaration).modifiers))
|
||||||
)
|
)
|
||||||
return this.mangleName(<DeclarationStatement>parent) + "#" + name;
|
return this.mangleInternalName(<DeclarationStatement>parent) + "#" + name;
|
||||||
// otherwise fall through
|
// otherwise fall through
|
||||||
}
|
}
|
||||||
case NodeKind.ENUM:
|
case NodeKind.ENUM:
|
||||||
case NodeKind.ENUMVALUE:
|
case NodeKind.ENUMVALUE:
|
||||||
case NodeKind.NAMESPACE:
|
case NodeKind.NAMESPACE:
|
||||||
return this.mangleName(<DeclarationStatement>parent) + "." + name;
|
return this.mangleInternalName(<DeclarationStatement>parent) + "." + name;
|
||||||
|
|
||||||
case NodeKind.IMPORT: {
|
case NodeKind.IMPORT: {
|
||||||
const impParent: Node | null = (<ImportStatement>parent).parent;
|
const importParent: Node | null = (<ImportStatement>parent).parent;
|
||||||
if (impParent && impParent.kind == NodeKind.SOURCE)
|
if (importParent && importParent.kind == NodeKind.SOURCE)
|
||||||
return (<SourceNode>impParent).path + "/" + name;
|
return (<Source>importParent).path + "/" + name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NodeKind.VARIABLE: {
|
case NodeKind.VARIABLE: {
|
||||||
const varParent: Node | null = (<VariableStatement>parent).parent;
|
const variableParent: Node | null = (<VariableStatement>parent).parent;
|
||||||
if (varParent) {
|
if (variableParent) {
|
||||||
if (varParent.kind == NodeKind.SOURCE)
|
if (variableParent.kind == NodeKind.SOURCE)
|
||||||
return <SourceNode>varParent == this.sources[0] ? name : (<SourceNode>varParent).path + "/" + name;
|
return <Source>variableParent == this.sources[0] ? name : (<Source>variableParent).path + "/" + name;
|
||||||
if (varParent.kind == NodeKind.NAMESPACE)
|
if (variableParent.kind == NodeKind.NAMESPACE)
|
||||||
return this.mangleName(<DeclarationStatement>varParent) + "." + name;
|
return this.mangleInternalName(<DeclarationStatement>variableParent) + "." + name;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -396,34 +393,9 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
throw new Error("unexpected parent");
|
throw new Error("unexpected parent");
|
||||||
}
|
}
|
||||||
|
|
||||||
addClass(cl: Class): void {
|
|
||||||
cl.declaration.reflectionIndex = this.classes.length;
|
|
||||||
this.classes.push(cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
addEnum(en: Enum): void {
|
|
||||||
en.declaration.reflectionIndex = this.enums.length;
|
|
||||||
this.enums.push(en);
|
|
||||||
}
|
|
||||||
|
|
||||||
addFunction(fn: Function): void {
|
|
||||||
fn.declaration.reflectionIndex = this.functions.length;
|
|
||||||
this.functions.push(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
addGlobal(gl: GlobalVariable): void {
|
|
||||||
gl.declaration.reflectionIndex = this.globals.length;
|
|
||||||
this.globals.push(gl);
|
|
||||||
}
|
|
||||||
|
|
||||||
addNamespace(ns: Namespace): void {
|
|
||||||
ns.declaration.reflectionIndex = this.namespaces.length;
|
|
||||||
this.namespaces.push(ns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeBasicTypes(types: Map<string,Type>, target: Target) {
|
function initializeBasicTypes(types: Map<string,Type>, target: Target): void {
|
||||||
types.set("i8", Type.i8);
|
types.set("i8", Type.i8);
|
||||||
types.set("i16", Type.i16);
|
types.set("i16", Type.i16);
|
||||||
types.set("i32", Type.i32);
|
types.set("i32", Type.i32);
|
||||||
@ -435,5 +407,7 @@ function initializeBasicTypes(types: Map<string,Type>, target: Target) {
|
|||||||
types.set("u64", Type.u64);
|
types.set("u64", Type.u64);
|
||||||
types.set("usize", target == Target.WASM64 ? Type.usize64 : Type.usize32);
|
types.set("usize", target == Target.WASM64 ? Type.usize64 : Type.usize32);
|
||||||
types.set("bool", Type.bool);
|
types.set("bool", Type.bool);
|
||||||
|
types.set("f32", Type.f32);
|
||||||
|
types.set("f64", Type.f64);
|
||||||
types.set("void", Type.void);
|
types.set("void", Type.void);
|
||||||
}
|
}
|
||||||
|
@ -1,310 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Reflection objects are largely independent of their respective declarations in
|
|
||||||
order to make it easier to introduce internal objects.
|
|
||||||
|
|
||||||
Base
|
|
||||||
├ Class
|
|
||||||
├ Enum
|
|
||||||
├ Field
|
|
||||||
├ Function
|
|
||||||
│ └ Method
|
|
||||||
├ Import
|
|
||||||
├ Namespace
|
|
||||||
├ Source
|
|
||||||
├ Type ~ TypeKind
|
|
||||||
└ VariableBase
|
|
||||||
├ GlobalVariable
|
|
||||||
└ LocalVariable
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
ClassDeclaration,
|
|
||||||
DeclarationStatement,
|
|
||||||
EnumDeclaration,
|
|
||||||
Expression,
|
|
||||||
FunctionDeclaration,
|
|
||||||
ImportDeclaration,
|
|
||||||
ImportStatement,
|
|
||||||
MethodDeclaration,
|
|
||||||
ModifierKind,
|
|
||||||
NamespaceDeclaration,
|
|
||||||
Node,
|
|
||||||
FieldDeclaration,
|
|
||||||
SourceNode,
|
|
||||||
Statement,
|
|
||||||
NodeKind,
|
|
||||||
TypeParameter,
|
|
||||||
VariableDeclaration,
|
|
||||||
VariableStatement
|
|
||||||
} from "./ast";
|
|
||||||
import { DiagnosticMessage } from "./diagnostics";
|
|
||||||
import { Token, Tokenizer, Range } from "./tokenizer";
|
|
||||||
import { hasModifier } from "./parser";
|
|
||||||
import { normalizePath, trimExtension } from "./util";
|
|
||||||
|
|
||||||
export abstract class Base {
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
exportName: string | null = null;
|
|
||||||
|
|
||||||
constructor(name: string) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isExport(): bool { return this.exportName != null; }
|
|
||||||
|
|
||||||
exportAs(exportName: string): this {
|
|
||||||
this.exportName = exportName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum TypeKind {
|
|
||||||
I8,
|
|
||||||
I16,
|
|
||||||
I32,
|
|
||||||
I64,
|
|
||||||
ISIZE,
|
|
||||||
U8,
|
|
||||||
U16,
|
|
||||||
U32,
|
|
||||||
U64,
|
|
||||||
USIZE,
|
|
||||||
F32,
|
|
||||||
F64,
|
|
||||||
BOOL,
|
|
||||||
VOID
|
|
||||||
}
|
|
||||||
|
|
||||||
export function typeKindToString(kind: TypeKind): string {
|
|
||||||
switch (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 "isize";
|
|
||||||
case TypeKind.U8: return "u8";
|
|
||||||
case TypeKind.U16: return "u16";
|
|
||||||
case TypeKind.U32: return "u32";
|
|
||||||
case TypeKind.U64: return "u64";
|
|
||||||
case TypeKind.USIZE: return "usize";
|
|
||||||
case TypeKind.F32: return "f32";
|
|
||||||
case TypeKind.F64: return "f64";
|
|
||||||
case TypeKind.BOOL: return "bool";
|
|
||||||
case TypeKind.VOID: return "void";
|
|
||||||
}
|
|
||||||
return "invalid";
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Type extends Base {
|
|
||||||
|
|
||||||
kind: TypeKind;
|
|
||||||
size: i32;
|
|
||||||
|
|
||||||
constructor(kind: TypeKind, size: i32) {
|
|
||||||
super(typeKindToString(kind));
|
|
||||||
this.kind = kind;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
get bitSize(): i32 { return this.size << 3; }
|
|
||||||
get smallIntegerShift(): i32 { return 32 - (this.size << 3); }
|
|
||||||
get smallIntegerMask(): i32 { return -1 >>> 32 - (this.size << 3); }
|
|
||||||
|
|
||||||
get isAnyInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.USIZE; }
|
|
||||||
get isSmallInteger(): bool { return this.size == 1 || this.size == 2; }
|
|
||||||
get isLongInteger(): bool { return this.size == 8 && this.kind != TypeKind.F64; }
|
|
||||||
get isUnsignedInteger(): bool { return this.kind >= TypeKind.U8 && this.kind <= TypeKind.USIZE; }
|
|
||||||
get isSignedInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.ISIZE; }
|
|
||||||
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
|
|
||||||
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
return typeKindToString(this.kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly i8: Type = new Type(TypeKind.I8, 1);
|
|
||||||
static readonly i16: Type = new Type(TypeKind.I16, 2);
|
|
||||||
static readonly i32: Type = new Type(TypeKind.I32, 4);
|
|
||||||
static readonly i64: Type = new Type(TypeKind.I64, 8);
|
|
||||||
static readonly isize32: Type = new Type(TypeKind.I32, 4);
|
|
||||||
static readonly isize64: Type = new Type(TypeKind.I64, 8);
|
|
||||||
static readonly u8: Type = new Type(TypeKind.U8, 1);
|
|
||||||
static readonly u16: Type = new Type(TypeKind.U16, 2);
|
|
||||||
static readonly u32: Type = new Type(TypeKind.U32, 4);
|
|
||||||
static readonly u64: Type = new Type(TypeKind.U64, 8);
|
|
||||||
static readonly usize32: Type = new Type(TypeKind.U32, 4);
|
|
||||||
static readonly usize64: Type = new Type(TypeKind.U64, 8);
|
|
||||||
static readonly f32: Type = new Type(TypeKind.F32, 4);
|
|
||||||
static readonly f64: Type = new Type(TypeKind.F64, 8);
|
|
||||||
static readonly bool: Type = new Type(TypeKind.BOOL, 1);
|
|
||||||
static readonly void: Type = new Type(TypeKind.VOID, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Source extends SourceNode {
|
|
||||||
|
|
||||||
text: string;
|
|
||||||
tokenizer: Tokenizer | null = null;
|
|
||||||
statements: Statement[];
|
|
||||||
isEntry: bool;
|
|
||||||
normalizedPath: string;
|
|
||||||
|
|
||||||
constructor(path: string, text: string, isEntry: bool = false) {
|
|
||||||
super();
|
|
||||||
this.range = new Range(this, 0, text.length);
|
|
||||||
this.path = path;
|
|
||||||
this.text = text;
|
|
||||||
this.statements = new Array();
|
|
||||||
this.isEntry = isEntry;
|
|
||||||
this.normalizedPath = normalizePath(trimExtension(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
get isDeclaration(): bool { return !this.isEntry && this.path.endsWith(".d.ts"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Import extends Base {
|
|
||||||
|
|
||||||
declaration: ImportDeclaration | null;
|
|
||||||
externalName: string;
|
|
||||||
|
|
||||||
static create(declaration: ImportStatement): Import[] {
|
|
||||||
const count: i32 = declaration.declarations.length;
|
|
||||||
const imports: Import[] = new Array(count);
|
|
||||||
for (let i: i32 = 0; i < count; ++i) {
|
|
||||||
const decl: ImportDeclaration = declaration.declarations[i];
|
|
||||||
const imprt: Import = new Import(decl.identifier.name);
|
|
||||||
imprt.declaration = decl;
|
|
||||||
imprt.externalName = decl.externalIdentifier.name;
|
|
||||||
imports[i] = imprt;
|
|
||||||
}
|
|
||||||
return imports;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class Variable extends Base {
|
|
||||||
type: Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GlobalVariable extends Variable {
|
|
||||||
|
|
||||||
declaration: VariableDeclaration;
|
|
||||||
mutable: bool;
|
|
||||||
|
|
||||||
static create(declaration: VariableStatement): GlobalVariable[] {
|
|
||||||
const mutable: bool = hasModifier(ModifierKind.CONST, declaration.modifiers);
|
|
||||||
const count: i32 = declaration.members.length;
|
|
||||||
const variables: GlobalVariable[] = new Array(count);
|
|
||||||
for (let i: i32 = 0; i < count; ++i) {
|
|
||||||
const decl: VariableDeclaration = declaration.members[i];
|
|
||||||
const variable: GlobalVariable = new GlobalVariable(decl.identifier.name);
|
|
||||||
variable.declaration = decl;
|
|
||||||
variable.mutable = mutable;
|
|
||||||
variables[i] = variable;
|
|
||||||
}
|
|
||||||
return variables;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LocalVariable extends Variable {
|
|
||||||
|
|
||||||
declaration: VariableDeclaration;
|
|
||||||
index: i32;
|
|
||||||
|
|
||||||
static create(declaration: VariableStatement, index: i32): LocalVariable[] {
|
|
||||||
const count: i32 = declaration.members.length;
|
|
||||||
const variables: LocalVariable[] = new Array(count);
|
|
||||||
for (let i: i32 = 0; i < count; ++i) {
|
|
||||||
const decl: VariableDeclaration = declaration.members[i];
|
|
||||||
const variable: LocalVariable = new LocalVariable(decl.identifier.name);
|
|
||||||
variable.declaration = decl;
|
|
||||||
variable.index = index;
|
|
||||||
variables[i] = variable;
|
|
||||||
}
|
|
||||||
return variables;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Namespace extends Base {
|
|
||||||
|
|
||||||
declaration: NamespaceDeclaration;
|
|
||||||
members: Base[];
|
|
||||||
|
|
||||||
static create(declaration: NamespaceDeclaration): Namespace {
|
|
||||||
const ns: Namespace = new Namespace(declaration.identifier.name);
|
|
||||||
ns.declaration = declaration;
|
|
||||||
const members: Base[] = ns.members = new Array();
|
|
||||||
// TODO: insert members
|
|
||||||
return ns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Enum extends Base {
|
|
||||||
|
|
||||||
declaration: EnumDeclaration;
|
|
||||||
isConst: bool;
|
|
||||||
values: Map<string,Expression | null> = new Map();
|
|
||||||
|
|
||||||
static create(declaration: EnumDeclaration): Enum {
|
|
||||||
const enm: Enum = new Enum(declaration.identifier.name);
|
|
||||||
enm.declaration = declaration;
|
|
||||||
enm.isConst = hasModifier(ModifierKind.CONST, declaration.modifiers);
|
|
||||||
// TODO: insert values
|
|
||||||
return enm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Function extends Base {
|
|
||||||
|
|
||||||
declaration: FunctionDeclaration;
|
|
||||||
typeArguments: Type[];
|
|
||||||
returnType: Type;
|
|
||||||
statements: Statement[];
|
|
||||||
|
|
||||||
static create(declaration: FunctionDeclaration, typeArguments: Type[]): Function {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Class extends Base {
|
|
||||||
|
|
||||||
declaration: ClassDeclaration;
|
|
||||||
typeArguments: Type[];
|
|
||||||
baseClass: Class | null;
|
|
||||||
memberNames: Set<string>;
|
|
||||||
methods: Map<string,Method>;
|
|
||||||
fields: Map<string,Field>;
|
|
||||||
|
|
||||||
static create(declaration: ClassDeclaration, typeArguments: Type[]): Class {
|
|
||||||
const clazz: Class = new Class(declaration.identifier.name);
|
|
||||||
clazz.typeArguments = typeArguments;
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Method extends Function {
|
|
||||||
|
|
||||||
declaration: MethodDeclaration; // more specific
|
|
||||||
isInstance: bool;
|
|
||||||
|
|
||||||
static create(declaration: MethodDeclaration, typeArguments: Type[]): Method {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Field extends Base {
|
|
||||||
|
|
||||||
declaration: FieldDeclaration | null;
|
|
||||||
type: Type;
|
|
||||||
offset: i32;
|
|
||||||
initializer: Expression | null;
|
|
||||||
|
|
||||||
static create(declaration: FieldDeclaration, offset: i32): Field {
|
|
||||||
const field: Field = new Field(declaration.identifier.name);
|
|
||||||
field.declaration = declaration;
|
|
||||||
field.offset = offset;
|
|
||||||
field.initializer = declaration.initializer;
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics";
|
||||||
import { Source } from "./reflection";
|
import { Source } from "./ast";
|
||||||
import { I64, CharCode, isLineBreak } from "./util";
|
import { I64, CharCode, isLineBreak } from "./util";
|
||||||
|
|
||||||
export enum Token {
|
export enum Token {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"node"
|
"node"
|
||||||
],
|
],
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"alwaysStrict": true,
|
"alwaysStrict": true,
|
||||||
"outDir": "../out"
|
"outDir": "../out"
|
||||||
@ -28,7 +29,10 @@
|
|||||||
"program.ts",
|
"program.ts",
|
||||||
"reflection.ts",
|
"reflection.ts",
|
||||||
"tokenizer.ts",
|
"tokenizer.ts",
|
||||||
|
"types.ts",
|
||||||
"util.ts",
|
"util.ts",
|
||||||
"util/i64.ts"
|
"util/charcode.ts",
|
||||||
|
"util/i64.ts",
|
||||||
|
"util/path.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
138
src/types.ts
Normal file
138
src/types.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
export const enum TypeKind {
|
||||||
|
|
||||||
|
// signed integers
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
ISIZE,
|
||||||
|
|
||||||
|
// unsigned integers
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
USIZE,
|
||||||
|
BOOL, // sic
|
||||||
|
|
||||||
|
// floats
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
|
||||||
|
VOID
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Type {
|
||||||
|
|
||||||
|
kind: TypeKind;
|
||||||
|
size: i32;
|
||||||
|
classType: ClassType | null;
|
||||||
|
nullable: bool = false;
|
||||||
|
nullableType: Type | null = null; // cached, of this type
|
||||||
|
|
||||||
|
constructor(kind: TypeKind, size: i32) {
|
||||||
|
this.kind = kind;
|
||||||
|
this.size = size;
|
||||||
|
this.classType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get smallIntegerShift(): i32 { return 32 - this.size; }
|
||||||
|
get smallIntegerMask(): i32 { return -1 >>> (32 - this.size); }
|
||||||
|
|
||||||
|
get isAnyInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.BOOL; }
|
||||||
|
get isSmallInteger(): bool { return this.size != 0 && this.size < 32; }
|
||||||
|
get isLongInteger(): bool { return this.size == 64 && this.kind != TypeKind.F64; }
|
||||||
|
get isUnsignedInteger(): bool { return this.kind >= TypeKind.U8 && this.kind <= TypeKind.BOOL; }
|
||||||
|
get isSignedInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.ISIZE; }
|
||||||
|
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
|
||||||
|
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
|
||||||
|
|
||||||
|
asClass(classType: ClassType): Type {
|
||||||
|
const ret: Type = new Type(this.kind, this.size);
|
||||||
|
ret.classType = classType;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
asNullable(): Type {
|
||||||
|
if (!this.nullableType)
|
||||||
|
(this.nullableType = new Type(this.kind, this.size)).nullable = true;
|
||||||
|
return <Type>this.nullableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
switch (this.kind) {
|
||||||
|
case TypeKind.I8: return "i8";
|
||||||
|
case TypeKind.I16: return "i16";
|
||||||
|
case TypeKind.I32: return "i32";
|
||||||
|
case TypeKind.ISIZE: return "isize";
|
||||||
|
case TypeKind.U8: return "u8";
|
||||||
|
case TypeKind.U16: return "u16";
|
||||||
|
case TypeKind.U32: return "u32";
|
||||||
|
case TypeKind.U64: return "u64";
|
||||||
|
case TypeKind.USIZE: return "usize";
|
||||||
|
case TypeKind.BOOL: return "bool";
|
||||||
|
case TypeKind.F32: return "f32";
|
||||||
|
case TypeKind.F64: return "f64";
|
||||||
|
case TypeKind.VOID: return "void";
|
||||||
|
default:
|
||||||
|
throw new Error("unexpected type kind");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly i8: Type = new Type(TypeKind.I8, 8);
|
||||||
|
static readonly i16: Type = new Type(TypeKind.I16, 16);
|
||||||
|
static readonly i32: Type = new Type(TypeKind.I32, 32);
|
||||||
|
static readonly i64: Type = new Type(TypeKind.I64, 64);
|
||||||
|
static readonly isize32: Type = new Type(TypeKind.I32, 32);
|
||||||
|
static readonly isize64: Type = new Type(TypeKind.I64, 64);
|
||||||
|
static readonly u8: Type = new Type(TypeKind.U8, 8);
|
||||||
|
static readonly u16: Type = new Type(TypeKind.U16, 16);
|
||||||
|
static readonly u32: Type = new Type(TypeKind.U32, 32);
|
||||||
|
static readonly u64: Type = new Type(TypeKind.U64, 64);
|
||||||
|
static readonly usize32: Type = new Type(TypeKind.U32, 32);
|
||||||
|
static readonly usize64: Type = new Type(TypeKind.U64, 64);
|
||||||
|
static readonly bool: Type = new Type(TypeKind.BOOL, 1);
|
||||||
|
static readonly f32: Type = new Type(TypeKind.F32, 32);
|
||||||
|
static readonly f64: Type = new Type(TypeKind.F64, 64);
|
||||||
|
static readonly void: Type = new Type(TypeKind.VOID, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FunctionType {
|
||||||
|
|
||||||
|
returnType: Type;
|
||||||
|
parameterTypes: Type[];
|
||||||
|
additionalLocals: Type[];
|
||||||
|
typeArgumentsMap: Map<string, Type> | null = null;
|
||||||
|
|
||||||
|
private breakMajor: i32 = 0;
|
||||||
|
private breakMinor: i32 = 0;
|
||||||
|
|
||||||
|
constructor(returnType: Type, parameterTypes: Type[]) {
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.parameterTypes = parameterTypes;
|
||||||
|
this.additionalLocals = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
enterBreakContext(): string {
|
||||||
|
if (!this.breakMinor)
|
||||||
|
this.breakMajor++;
|
||||||
|
return this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveBreakContext(): void {
|
||||||
|
if (--this.breakMinor < 0)
|
||||||
|
throw new Error("unexpected unbalanced break context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClassType {
|
||||||
|
|
||||||
|
type: Type;
|
||||||
|
typeArgumentsMap: Map<string, Type> | null = null;
|
||||||
|
base: ClassType | null;
|
||||||
|
|
||||||
|
constructor(usizeType: Type, base: ClassType | null = null) {
|
||||||
|
this.type = usizeType.asClass(this);
|
||||||
|
this.base = base;
|
||||||
|
}
|
||||||
|
}
|
235
src/util.ts
235
src/util.ts
@ -1,235 +1,4 @@
|
|||||||
export { I64, U64 } from "./util/i64";
|
export { I64, U64 } from "./util/i64";
|
||||||
|
export { CharCode, isLineBreak} from "./util/charcode";
|
||||||
export const enum CharCode {
|
export { normalize as normalizePath, resolve as resolvePath, dirname } from "./util/path";
|
||||||
|
|
||||||
NULL = 0,
|
|
||||||
LINEFEED = 0x0A,
|
|
||||||
CARRIAGERETURN = 0x0D,
|
|
||||||
LINESEPARATOR = 0x2028,
|
|
||||||
PARAGRAPHSEPARATOR = 0x2029,
|
|
||||||
NEXTLINE = 0x0085,
|
|
||||||
|
|
||||||
SPACE = 0x20,
|
|
||||||
NONBREAKINGSPACE = 0xA0,
|
|
||||||
ENQUAD = 0x2000,
|
|
||||||
EMQUAD = 0x2001,
|
|
||||||
ENSPACE = 0x2002,
|
|
||||||
EMSPACE = 0x2003,
|
|
||||||
THREEPEREMSPACE = 0x2004,
|
|
||||||
FOURPEREMSPACE = 0x2005,
|
|
||||||
SIXPEREMSPACE = 0x2006,
|
|
||||||
FIGURESPACE = 0x2007,
|
|
||||||
PUNCTUATIONSPACE = 0x2008,
|
|
||||||
THINSPACE = 0x2009,
|
|
||||||
HAIRSPACE = 0x200A,
|
|
||||||
ZEROWIDTHSPACE = 0x200B,
|
|
||||||
NARRINOBREAKSPACE = 0x202F,
|
|
||||||
IDEOGRAPHICSPACE = 0x3000,
|
|
||||||
MATHEMATICALSPACE = 0x205F,
|
|
||||||
OGHAM = 0x1680,
|
|
||||||
|
|
||||||
_ = 0x5F,
|
|
||||||
$ = 0x24,
|
|
||||||
|
|
||||||
_0 = 0x30,
|
|
||||||
_1 = 0x31,
|
|
||||||
_2 = 0x32,
|
|
||||||
_3 = 0x33,
|
|
||||||
_4 = 0x34,
|
|
||||||
_5 = 0x35,
|
|
||||||
_6 = 0x36,
|
|
||||||
_7 = 0x37,
|
|
||||||
_8 = 0x38,
|
|
||||||
_9 = 0x39,
|
|
||||||
|
|
||||||
a = 0x61,
|
|
||||||
b = 0x62,
|
|
||||||
c = 0x63,
|
|
||||||
d = 0x64,
|
|
||||||
e = 0x65,
|
|
||||||
f = 0x66,
|
|
||||||
g = 0x67,
|
|
||||||
h = 0x68,
|
|
||||||
i = 0x69,
|
|
||||||
j = 0x6A,
|
|
||||||
k = 0x6B,
|
|
||||||
l = 0x6C,
|
|
||||||
m = 0x6D,
|
|
||||||
n = 0x6E,
|
|
||||||
o = 0x6F,
|
|
||||||
p = 0x70,
|
|
||||||
q = 0x71,
|
|
||||||
r = 0x72,
|
|
||||||
s = 0x73,
|
|
||||||
t = 0x74,
|
|
||||||
u = 0x75,
|
|
||||||
v = 0x76,
|
|
||||||
w = 0x77,
|
|
||||||
x = 0x78,
|
|
||||||
y = 0x79,
|
|
||||||
z = 0x7A,
|
|
||||||
|
|
||||||
A = 0x41,
|
|
||||||
B = 0x42,
|
|
||||||
C = 0x43,
|
|
||||||
D = 0x44,
|
|
||||||
E = 0x45,
|
|
||||||
F = 0x46,
|
|
||||||
G = 0x47,
|
|
||||||
H = 0x48,
|
|
||||||
I = 0x49,
|
|
||||||
J = 0x4A,
|
|
||||||
K = 0x4B,
|
|
||||||
L = 0x4C,
|
|
||||||
M = 0x4D,
|
|
||||||
N = 0x4E,
|
|
||||||
O = 0x4F,
|
|
||||||
P = 0x50,
|
|
||||||
Q = 0x51,
|
|
||||||
R = 0x52,
|
|
||||||
S = 0x53,
|
|
||||||
T = 0x54,
|
|
||||||
U = 0x55,
|
|
||||||
V = 0x56,
|
|
||||||
W = 0x57,
|
|
||||||
X = 0x58,
|
|
||||||
Y = 0x59,
|
|
||||||
Z = 0x5a,
|
|
||||||
|
|
||||||
AMPERSAND = 0x26,
|
|
||||||
ASTERISK = 0x2A,
|
|
||||||
AT = 0x40,
|
|
||||||
BACKSLASH = 0x5C,
|
|
||||||
BACKTICK = 0x60,
|
|
||||||
BAR = 0x7C,
|
|
||||||
CARET = 0x5E,
|
|
||||||
CLOSEBRACE = 0x7D,
|
|
||||||
CLOSEBRACKET = 0x5D,
|
|
||||||
CLOSEPAREN = 0x29,
|
|
||||||
COLON = 0x3A,
|
|
||||||
COMMA = 0x2C,
|
|
||||||
DOT = 0x2E,
|
|
||||||
DOUBLEQUOTE = 0x22,
|
|
||||||
EQUALS = 0x3D,
|
|
||||||
EXCLAMATION = 0x21,
|
|
||||||
GREATERTHAN = 0x3E,
|
|
||||||
HASH = 0x23,
|
|
||||||
LESSTHAN = 0x3C,
|
|
||||||
MINUS = 0x2D,
|
|
||||||
OPENBRACE = 0x7B,
|
|
||||||
OPENBRACKET = 0x5B,
|
|
||||||
OPENPAREN = 0x28,
|
|
||||||
PERCENT = 0x25,
|
|
||||||
PLUS = 0x2B,
|
|
||||||
QUESTION = 0x3F,
|
|
||||||
SEMICOLON = 0x3B,
|
|
||||||
SINGLEQUOTE = 0x27,
|
|
||||||
SLASH = 0x2F,
|
|
||||||
TILDE = 0x7E,
|
|
||||||
|
|
||||||
BACKSPACE = 0x08,
|
|
||||||
FORMFEED = 0x0C,
|
|
||||||
BYTEORDERMARK = 0xFEFF,
|
|
||||||
TAB = 0x09,
|
|
||||||
VERTICALTAB = 0x0B
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isLineBreak(c: i32): bool {
|
|
||||||
return c == CharCode.LINEFEED
|
|
||||||
|| c == CharCode.CARRIAGERETURN
|
|
||||||
|| c == CharCode.LINESEPARATOR
|
|
||||||
|| c == CharCode.PARAGRAPHSEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
||||||
|
|
||||||
export function normalizePath(path: string, separator: CharCode = CharCode.SLASH): string {
|
|
||||||
// expects a relative path
|
|
||||||
|
|
||||||
let pos: i32 = 0;
|
|
||||||
let len: i32 = path.length;
|
|
||||||
|
|
||||||
// trim leading './'
|
|
||||||
while (pos + 1 < len && path.charCodeAt(pos) == CharCode.DOT && path.charCodeAt(pos + 1) == separator)
|
|
||||||
pos += 2;
|
|
||||||
if (pos > 0) {
|
|
||||||
path = path.substring(pos);
|
|
||||||
len -= pos;
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let atEnd: bool;
|
|
||||||
while (pos + 1 < len) {
|
|
||||||
atEnd = false;
|
|
||||||
|
|
||||||
// we are only interested in '/.' sequences ...
|
|
||||||
if (path.charCodeAt(pos) == separator && path.charCodeAt(pos + 1) == CharCode.DOT) {
|
|
||||||
|
|
||||||
// '/.' ( '/' | $ )
|
|
||||||
if (
|
|
||||||
(atEnd = pos + 2 == len)
|
|
||||||
||
|
|
||||||
pos + 2 < len && path.charCodeAt(pos + 2) == separator
|
|
||||||
) {
|
|
||||||
path = atEnd
|
|
||||||
? path.substring(0, pos)
|
|
||||||
: path.substring(0, pos) + path.substring(pos + 2);
|
|
||||||
len -= 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// '/.' ( './' | '.' $ )
|
|
||||||
if (
|
|
||||||
(atEnd = pos + 3 == len) && path.charCodeAt(pos + 2) == CharCode.DOT
|
|
||||||
||
|
|
||||||
pos + 3 < len && path.charCodeAt(pos + 2) == CharCode.DOT && path.charCodeAt(pos + 3) == separator
|
|
||||||
) {
|
|
||||||
|
|
||||||
// find preceeding '/'
|
|
||||||
let ipos: i32 = pos;
|
|
||||||
while (--ipos >= 0) {
|
|
||||||
if (path.charCodeAt(ipos) == separator) {
|
|
||||||
if (pos - ipos != 3 || path.charCodeAt(ipos + 1) != CharCode.DOT || path.charCodeAt(ipos + 2) != CharCode.DOT) { // exclude '..' itself
|
|
||||||
path = atEnd
|
|
||||||
? path.substring(0, ipos)
|
|
||||||
: path.substring(0, ipos) + path.substring(pos + 3);
|
|
||||||
len -= pos + 3 - ipos;
|
|
||||||
pos = ipos - 1; // incremented again at end of loop
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there's no preceeding '/', trim start if non-empty
|
|
||||||
if (ipos < 0 && pos > 0) {
|
|
||||||
if (pos != 2 || path.charCodeAt(0) != CharCode.DOT || path.charCodeAt(1) != CharCode.DOT) { // exclude '..' itself
|
|
||||||
path = path.substring(pos + 4);
|
|
||||||
len = path.length;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
return len > 0 ? path : ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function dirname(normalizedPath: string, separator: CharCode = CharCode.SLASH): string {
|
|
||||||
let pos: i32 = normalizedPath.length;
|
|
||||||
while (--pos > 0)
|
|
||||||
if (normalizedPath.charCodeAt(pos) == separator)
|
|
||||||
return normalizedPath.substring(0, pos);
|
|
||||||
return ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolvePath(normalizedPath: string, normalizedOrigin: string, separator: CharCode = CharCode.SLASH): string {
|
|
||||||
return normalizePath(dirname(normalizedOrigin, separator) + String.fromCharCode(separator) + normalizedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function trimExtension(path: string): string {
|
|
||||||
const len: i32 = path.length;
|
|
||||||
if (len > 3 && path.charCodeAt(len - 3) == CharCode.DOT && (path.charCodeAt(len - 2) == CharCode.t || path.charCodeAt(len - 2) == CharCode.a) && path.charCodeAt(len - 1) == CharCode.s)
|
|
||||||
return path.substring(0, len - 3);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
140
src/util/charcode.ts
Normal file
140
src/util/charcode.ts
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
export const enum CharCode {
|
||||||
|
|
||||||
|
NULL = 0,
|
||||||
|
LINEFEED = 0x0A,
|
||||||
|
CARRIAGERETURN = 0x0D,
|
||||||
|
LINESEPARATOR = 0x2028,
|
||||||
|
PARAGRAPHSEPARATOR = 0x2029,
|
||||||
|
NEXTLINE = 0x0085,
|
||||||
|
|
||||||
|
SPACE = 0x20,
|
||||||
|
NONBREAKINGSPACE = 0xA0,
|
||||||
|
ENQUAD = 0x2000,
|
||||||
|
EMQUAD = 0x2001,
|
||||||
|
ENSPACE = 0x2002,
|
||||||
|
EMSPACE = 0x2003,
|
||||||
|
THREEPEREMSPACE = 0x2004,
|
||||||
|
FOURPEREMSPACE = 0x2005,
|
||||||
|
SIXPEREMSPACE = 0x2006,
|
||||||
|
FIGURESPACE = 0x2007,
|
||||||
|
PUNCTUATIONSPACE = 0x2008,
|
||||||
|
THINSPACE = 0x2009,
|
||||||
|
HAIRSPACE = 0x200A,
|
||||||
|
ZEROWIDTHSPACE = 0x200B,
|
||||||
|
NARRINOBREAKSPACE = 0x202F,
|
||||||
|
IDEOGRAPHICSPACE = 0x3000,
|
||||||
|
MATHEMATICALSPACE = 0x205F,
|
||||||
|
OGHAM = 0x1680,
|
||||||
|
|
||||||
|
_ = 0x5F,
|
||||||
|
$ = 0x24,
|
||||||
|
|
||||||
|
_0 = 0x30,
|
||||||
|
_1 = 0x31,
|
||||||
|
_2 = 0x32,
|
||||||
|
_3 = 0x33,
|
||||||
|
_4 = 0x34,
|
||||||
|
_5 = 0x35,
|
||||||
|
_6 = 0x36,
|
||||||
|
_7 = 0x37,
|
||||||
|
_8 = 0x38,
|
||||||
|
_9 = 0x39,
|
||||||
|
|
||||||
|
a = 0x61,
|
||||||
|
b = 0x62,
|
||||||
|
c = 0x63,
|
||||||
|
d = 0x64,
|
||||||
|
e = 0x65,
|
||||||
|
f = 0x66,
|
||||||
|
g = 0x67,
|
||||||
|
h = 0x68,
|
||||||
|
i = 0x69,
|
||||||
|
j = 0x6A,
|
||||||
|
k = 0x6B,
|
||||||
|
l = 0x6C,
|
||||||
|
m = 0x6D,
|
||||||
|
n = 0x6E,
|
||||||
|
o = 0x6F,
|
||||||
|
p = 0x70,
|
||||||
|
q = 0x71,
|
||||||
|
r = 0x72,
|
||||||
|
s = 0x73,
|
||||||
|
t = 0x74,
|
||||||
|
u = 0x75,
|
||||||
|
v = 0x76,
|
||||||
|
w = 0x77,
|
||||||
|
x = 0x78,
|
||||||
|
y = 0x79,
|
||||||
|
z = 0x7A,
|
||||||
|
|
||||||
|
A = 0x41,
|
||||||
|
B = 0x42,
|
||||||
|
C = 0x43,
|
||||||
|
D = 0x44,
|
||||||
|
E = 0x45,
|
||||||
|
F = 0x46,
|
||||||
|
G = 0x47,
|
||||||
|
H = 0x48,
|
||||||
|
I = 0x49,
|
||||||
|
J = 0x4A,
|
||||||
|
K = 0x4B,
|
||||||
|
L = 0x4C,
|
||||||
|
M = 0x4D,
|
||||||
|
N = 0x4E,
|
||||||
|
O = 0x4F,
|
||||||
|
P = 0x50,
|
||||||
|
Q = 0x51,
|
||||||
|
R = 0x52,
|
||||||
|
S = 0x53,
|
||||||
|
T = 0x54,
|
||||||
|
U = 0x55,
|
||||||
|
V = 0x56,
|
||||||
|
W = 0x57,
|
||||||
|
X = 0x58,
|
||||||
|
Y = 0x59,
|
||||||
|
Z = 0x5a,
|
||||||
|
|
||||||
|
AMPERSAND = 0x26,
|
||||||
|
ASTERISK = 0x2A,
|
||||||
|
AT = 0x40,
|
||||||
|
BACKSLASH = 0x5C,
|
||||||
|
BACKTICK = 0x60,
|
||||||
|
BAR = 0x7C,
|
||||||
|
CARET = 0x5E,
|
||||||
|
CLOSEBRACE = 0x7D,
|
||||||
|
CLOSEBRACKET = 0x5D,
|
||||||
|
CLOSEPAREN = 0x29,
|
||||||
|
COLON = 0x3A,
|
||||||
|
COMMA = 0x2C,
|
||||||
|
DOT = 0x2E,
|
||||||
|
DOUBLEQUOTE = 0x22,
|
||||||
|
EQUALS = 0x3D,
|
||||||
|
EXCLAMATION = 0x21,
|
||||||
|
GREATERTHAN = 0x3E,
|
||||||
|
HASH = 0x23,
|
||||||
|
LESSTHAN = 0x3C,
|
||||||
|
MINUS = 0x2D,
|
||||||
|
OPENBRACE = 0x7B,
|
||||||
|
OPENBRACKET = 0x5B,
|
||||||
|
OPENPAREN = 0x28,
|
||||||
|
PERCENT = 0x25,
|
||||||
|
PLUS = 0x2B,
|
||||||
|
QUESTION = 0x3F,
|
||||||
|
SEMICOLON = 0x3B,
|
||||||
|
SINGLEQUOTE = 0x27,
|
||||||
|
SLASH = 0x2F,
|
||||||
|
TILDE = 0x7E,
|
||||||
|
|
||||||
|
BACKSPACE = 0x08,
|
||||||
|
FORMFEED = 0x0C,
|
||||||
|
BYTEORDERMARK = 0xFEFF,
|
||||||
|
TAB = 0x09,
|
||||||
|
VERTICALTAB = 0x0B
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLineBreak(c: CharCode): bool {
|
||||||
|
return c == CharCode.LINEFEED
|
||||||
|
|| c == CharCode.CARRIAGERETURN
|
||||||
|
|| c == CharCode.LINESEPARATOR
|
||||||
|
|| c == CharCode.PARAGRAPHSEPARATOR;
|
||||||
|
}
|
90
src/util/path.ts
Normal file
90
src/util/path.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { CharCode } from "./charcode";
|
||||||
|
|
||||||
|
export function normalize(path: string, trimExtension: bool = false, separator: CharCode = CharCode.SLASH): string {
|
||||||
|
// expects a relative path
|
||||||
|
|
||||||
|
let pos: i32 = 0;
|
||||||
|
let len: i32 = path.length;
|
||||||
|
|
||||||
|
// trim leading './'
|
||||||
|
while (pos + 1 < len && path.charCodeAt(pos) == CharCode.DOT && path.charCodeAt(pos + 1) == separator)
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// trim extension if requested
|
||||||
|
if (trimExtension && len > pos + 3 && path.charCodeAt(len - 3) == CharCode.DOT && (path.charCodeAt(len - 2) == CharCode.t || path.charCodeAt(len - 2) == CharCode.a) && path.charCodeAt(len - 1) == CharCode.s)
|
||||||
|
len = len - 3;
|
||||||
|
|
||||||
|
if (pos > 0 || len < path.length) {
|
||||||
|
path = path.substring(pos, len);
|
||||||
|
len -= pos;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let atEnd: bool;
|
||||||
|
while (pos + 1 < len) {
|
||||||
|
atEnd = false;
|
||||||
|
|
||||||
|
// we are only interested in '/.' sequences ...
|
||||||
|
if (path.charCodeAt(pos) == separator && path.charCodeAt(pos + 1) == CharCode.DOT) {
|
||||||
|
|
||||||
|
// '/.' ( '/' | $ )
|
||||||
|
if (
|
||||||
|
(atEnd = pos + 2 == len)
|
||||||
|
||
|
||||||
|
pos + 2 < len && path.charCodeAt(pos + 2) == separator
|
||||||
|
) {
|
||||||
|
path = atEnd
|
||||||
|
? path.substring(0, pos)
|
||||||
|
: path.substring(0, pos) + path.substring(pos + 2);
|
||||||
|
len -= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// '/.' ( './' | '.' $ )
|
||||||
|
if (
|
||||||
|
(atEnd = pos + 3 == len) && path.charCodeAt(pos + 2) == CharCode.DOT
|
||||||
|
||
|
||||||
|
pos + 3 < len && path.charCodeAt(pos + 2) == CharCode.DOT && path.charCodeAt(pos + 3) == separator
|
||||||
|
) {
|
||||||
|
|
||||||
|
// find preceeding '/'
|
||||||
|
let ipos: i32 = pos;
|
||||||
|
while (--ipos >= 0) {
|
||||||
|
if (path.charCodeAt(ipos) == separator) {
|
||||||
|
if (pos - ipos != 3 || path.charCodeAt(ipos + 1) != CharCode.DOT || path.charCodeAt(ipos + 2) != CharCode.DOT) { // exclude '..' itself
|
||||||
|
path = atEnd
|
||||||
|
? path.substring(0, ipos)
|
||||||
|
: path.substring(0, ipos) + path.substring(pos + 3);
|
||||||
|
len -= pos + 3 - ipos;
|
||||||
|
pos = ipos - 1; // incremented again at end of loop
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there's no preceeding '/', trim start if non-empty
|
||||||
|
if (ipos < 0 && pos > 0) {
|
||||||
|
if (pos != 2 || path.charCodeAt(0) != CharCode.DOT || path.charCodeAt(1) != CharCode.DOT) { // exclude '..' itself
|
||||||
|
path = path.substring(pos + 4);
|
||||||
|
len = path.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return len > 0 ? path : ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolve(normalizedPath: string, normalizedOrigin: string, separator: CharCode = CharCode.SLASH): string {
|
||||||
|
return normalize(dirname(normalizedOrigin, separator) + String.fromCharCode(separator) + normalizedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dirname(normalizedPath: string, separator: CharCode = CharCode.SLASH): string {
|
||||||
|
let pos: i32 = normalizedPath.length;
|
||||||
|
while (--pos > 0)
|
||||||
|
if (normalizedPath.charCodeAt(pos) == separator)
|
||||||
|
return normalizedPath.substring(0, pos);
|
||||||
|
return ".";
|
||||||
|
}
|
@ -3,10 +3,10 @@ import { Compiler } from "../src/compiler";
|
|||||||
import { Parser } from "../src/parser";
|
import { Parser } from "../src/parser";
|
||||||
|
|
||||||
const files: Map<string,string> = new Map([
|
const files: Map<string,string> = new Map([
|
||||||
["main", `import { Test } from "./a"; export { TestAlias } from "./d";`],
|
["main", `import { Test as TestAlias } from "./a"; export { TestAlias } from "./d"; if (1) {} export const a: i32 = 123;`],
|
||||||
["a", `export { Test } from "./b";`],
|
["a", `export { Test } from "./b";`],
|
||||||
["b", `export { Test } from "./c";`],
|
["b", `export { Test } from "./c";`],
|
||||||
["c", `export enum Test { ONE = 1 }`],
|
["c", `export enum Test { ONE = 1, TWO = 2 }`],
|
||||||
["d", `export { Test as TestAlias } from "./b";`]
|
["d", `export { Test as TestAlias } from "./b";`]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -24,14 +24,14 @@ const program = parser.finish();
|
|||||||
const compiler = new Compiler(program);
|
const compiler = new Compiler(program);
|
||||||
const module = compiler.compile();
|
const module = compiler.compile();
|
||||||
|
|
||||||
console.log("names", program.names);
|
console.log("names", program.names.keys());
|
||||||
console.log("exports", program.exports);
|
console.log("exports", program.exports.keys());
|
||||||
|
|
||||||
// module.optimize();
|
// module.optimize();
|
||||||
// module.validate(); // global initializers can't use i32.add etc. yet
|
// module.validate(); // global initializers can't use i32.add etc. yet
|
||||||
/* _BinaryenModulePrint(module.ref);
|
_BinaryenModulePrint(module.ref);
|
||||||
|
|
||||||
console.log("--- statements ---");
|
/* console.log("--- statements ---");
|
||||||
compiler.statements.forEach(stmt => {
|
compiler.statements.forEach(stmt => {
|
||||||
_BinaryenExpressionPrint(stmt);
|
_BinaryenExpressionPrint(stmt);
|
||||||
}); */
|
}); */
|
@ -2,3 +2,6 @@ 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()
|
||||||
|
function withdecorator(): void {
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user