mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-10 05:21:27 +00:00
Program elements and resolve infrastructure; Stdlib ideas; Restructuring
This commit is contained in:
parent
6e98c52f76
commit
d1c1178f25
107
assembly.d.ts
vendored
Normal file
107
assembly.d.ts
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// types
|
||||||
|
|
||||||
|
/** An 8-bit signed integer. */
|
||||||
|
declare type i8 = number;
|
||||||
|
/** A 16-bit signed integer. */
|
||||||
|
declare type i16 = number;
|
||||||
|
/** A 32-bit signed integer. */
|
||||||
|
declare type i32 = number;
|
||||||
|
/** A 64-bit signed integer. */
|
||||||
|
declare type i64 = number;
|
||||||
|
/** A 32-bit signed integer when targeting 32-bit WebAssembly or a 64-bit signed integer when targeting 64-bit WebAssembly. */
|
||||||
|
declare type isize = number;
|
||||||
|
/** An 8-bit unsigned integer. */
|
||||||
|
declare type u8 = number;
|
||||||
|
/** A 16-bit unsigned integer. */
|
||||||
|
declare type u16 = number;
|
||||||
|
/** A 32-bit unsigned integer. */
|
||||||
|
declare type u32 = number;
|
||||||
|
/** A 64-bit unsigned integer. */
|
||||||
|
declare type u64 = number;
|
||||||
|
/** A 32-bit unsigned integer when targeting 32-bit WebAssembly or a 64-bit unsigned integer when targeting 64-bit WebAssembly. */
|
||||||
|
declare type usize = number;
|
||||||
|
/** A 1-bit unsigned integer. */
|
||||||
|
declare type bool = any; // sic
|
||||||
|
/** A 32-bit float. */
|
||||||
|
declare type f32 = number;
|
||||||
|
/** A 64-bit float. */
|
||||||
|
declare type f64 = number;
|
||||||
|
|
||||||
|
// builtins
|
||||||
|
|
||||||
|
/** Performs the sign-agnostic rotate left operation on a 32-bit or 64-bit integer. */
|
||||||
|
declare function rotl<T>(value: T, shift: T): T;
|
||||||
|
/** Performs the sign-agnostic rotate right operation on a 32-bit or 64-bit integer. */
|
||||||
|
declare function rotr<T>(value: T, shift: T): T;
|
||||||
|
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */
|
||||||
|
declare function clz<T>(value: T): T;
|
||||||
|
/** Performs the sign-agnostic count tailing zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered trailing if the value is zero. */
|
||||||
|
declare function ctz<T>(value: T): T;
|
||||||
|
/** Performs the sign-agnostic count number of one bits operation on a 32-bit or 64-bit integer. */
|
||||||
|
declare function popcnt<T>(value: T): T;
|
||||||
|
|
||||||
|
/** Computes the absolute value of a 32-bit or 64-bit float. */
|
||||||
|
declare function abs<T>(value: T): T;
|
||||||
|
/** Performs the ceiling operation on a 32-bit or 64-bit float. */
|
||||||
|
declare function ceil<T>(value: T): T;
|
||||||
|
/** Performs the floor operation on a 32-bit or 64-bit float. */
|
||||||
|
declare function floor<T>(value: T): T;
|
||||||
|
/** Calculates the square root of a 32-bit or 64-bit float. */
|
||||||
|
declare function sqrt<T>(value: T): T;
|
||||||
|
/** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */
|
||||||
|
declare function trunc<T>(value: T): T;
|
||||||
|
/** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */
|
||||||
|
declare function nearest<T>(value: T): T;
|
||||||
|
/** Determines the minimum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
|
||||||
|
declare function min<T>(left: T, right: T): T;
|
||||||
|
/** Determines the maximum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
|
||||||
|
declare function max<T>(left: T, right: T): T;
|
||||||
|
/** Composes a 32-bit or 64-bit float from the magnitude of `x` and the sign of `y`. */
|
||||||
|
declare function copysign<T>(x: T, y: T): T;
|
||||||
|
|
||||||
|
/** Reinterprets the bits of a value of type `T1` as type `T2`. Valid reinterpretations are i32 to/from f32 and i64 to/from f64. */
|
||||||
|
declare function reinterpret<T1,T2>(value: T1): T2;
|
||||||
|
/** Returns the current memory size in units of pages. One page is 64kb. */
|
||||||
|
declare function current_memory(): i32;
|
||||||
|
/** Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous memory size in units of pages or `-1` on failure. */
|
||||||
|
declare function grow_memory(value: i32): i32;
|
||||||
|
/** Emits an unreachable operation that results in a runtime error when executed. */
|
||||||
|
declare function unreachable(): void;
|
||||||
|
|
||||||
|
/** Loads a value of the specified type from memory. */
|
||||||
|
declare function load<T>(offset: usize): T;
|
||||||
|
/** Stores a value of the specified type to memory. */
|
||||||
|
declare function store<T>(offset: usize, value: T): void;
|
||||||
|
/** Determines the byte size of the specified core or class type. Compiles to a constant. */
|
||||||
|
declare function sizeof<T>(): usize;
|
||||||
|
/** Gets the underlying pointer value of a class type. */
|
||||||
|
declare function pointerof<T>(cls: T): usize;
|
||||||
|
/** Creates a class type from its underlying pointer value. */
|
||||||
|
declare function classof<T>(ptr: usize): T;
|
||||||
|
|
||||||
|
// standard library
|
||||||
|
|
||||||
|
/** NaN (not a number) as a 32-bit or 64-bit float depending on context. */
|
||||||
|
declare const NaN: number;
|
||||||
|
/** Positive infinity as a 32-bit or 64-bit float depending on context. */
|
||||||
|
declare const Infinity: number;
|
||||||
|
|
||||||
|
/** Tests if a 32-bit or 64-bit float is NaN. */
|
||||||
|
declare function isNaN<T>(value: T): bool;
|
||||||
|
/** Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity. */
|
||||||
|
declare function isFinite<T>(value: T): bool;
|
||||||
|
|
||||||
|
/** A decorator marking a function or class as global. */
|
||||||
|
declare function global(name?: string): any;
|
||||||
|
/** A decorator marking a function as ideally being inlined. */
|
||||||
|
declare function inline(): any;
|
||||||
|
/** A decorator marking a class that manually manages its memory. */
|
||||||
|
declare function allocates(): any;
|
||||||
|
declare function operator(token: string, fn: any): any;
|
||||||
|
|
||||||
|
/// <reference path="./std/array.d.ts" />
|
||||||
|
/// <reference path="./std/map.d.ts" />
|
||||||
|
/// <reference path="./std/math.d.ts" />
|
||||||
|
/// <reference path="./std/memory.d.ts" />
|
||||||
|
/// <reference path="./std/set.d.ts" />
|
||||||
|
/// <reference path="./std/string.d.ts" />
|
176
src/ast.ts
176
src/ast.ts
@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER, PARENT_SUBST, STATIC_DELIMITER, INSTANCE_DELIMITER } from "./constants";
|
||||||
import { Token, Tokenizer, operatorTokenToString, Range } from "./tokenizer";
|
import { Token, Tokenizer, operatorTokenToString, Range } from "./tokenizer";
|
||||||
import { CharCode, I64, normalizePath, resolvePath } from "./util";
|
import { CharCode, I64, normalizePath, resolvePath } from "./util";
|
||||||
|
|
||||||
@ -139,59 +140,6 @@ export enum NodeKind {
|
|||||||
WHILE
|
WHILE
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeKindToString(kind: NodeKind): string {
|
|
||||||
switch (kind) {
|
|
||||||
case NodeKind.SOURCE: return "SOURCE";
|
|
||||||
case NodeKind.TYPE: return "TYPE";
|
|
||||||
case NodeKind.TYPEPARAMETER: return "TYPEPARAMETER";
|
|
||||||
case NodeKind.IDENTIFIER: return "IDENTIFIER";
|
|
||||||
case NodeKind.ASSERTION: return "ASSERTION";
|
|
||||||
case NodeKind.BINARY: return "BINARY";
|
|
||||||
case NodeKind.CALL: return "CALL";
|
|
||||||
case NodeKind.ELEMENTACCESS: return "ELEMENTACCESS";
|
|
||||||
case NodeKind.LITERAL: return "LITERAL";
|
|
||||||
case NodeKind.NEW: return "NEW";
|
|
||||||
case NodeKind.PARENTHESIZED: return "PARENTHESIZED";
|
|
||||||
case NodeKind.PROPERTYACCESS: return "PROPERTYACCESS";
|
|
||||||
case NodeKind.SELECT: return "SELECT";
|
|
||||||
case NodeKind.UNARYPOSTFIX: return "UNARYPOSTFIX";
|
|
||||||
case NodeKind.UNARYPREFIX: return "UNARYPREFIX";
|
|
||||||
case NodeKind.BLOCK: return "BLOCK";
|
|
||||||
case NodeKind.BREAK: return "BREAK";
|
|
||||||
case NodeKind.CLASS: return "CLASS";
|
|
||||||
case NodeKind.CONTINUE: return "CONTINUE";
|
|
||||||
case NodeKind.DO: return "DO";
|
|
||||||
case NodeKind.EMPTY: return "EMPTY";
|
|
||||||
case NodeKind.ENUM: return "ENUM";
|
|
||||||
case NodeKind.ENUMVALUE: return "ENUMVALUE";
|
|
||||||
case NodeKind.EXPORT: return "EXPORT";
|
|
||||||
case NodeKind.EXPORTIMPORT: return "EXPORTIMPORT";
|
|
||||||
case NodeKind.EXPRESSION: return "EXPRESSION";
|
|
||||||
case NodeKind.INTERFACE: return "INTERFACE";
|
|
||||||
case NodeKind.FALSE: return "FALSE";
|
|
||||||
case NodeKind.FOR: return "FOR";
|
|
||||||
case NodeKind.FUNCTION: return "FUNCTION";
|
|
||||||
case NodeKind.IF: return "IF";
|
|
||||||
case NodeKind.IMPORT: return "IMPORT";
|
|
||||||
case NodeKind.IMPORTDECLARATION: return "IMPORTDECLARATION";
|
|
||||||
case NodeKind.METHOD: return "METHOD";
|
|
||||||
case NodeKind.NAMESPACE: return "NAMESPACE";
|
|
||||||
case NodeKind.NULL: return "NULL";
|
|
||||||
case NodeKind.FIELD: return "PROPERTY";
|
|
||||||
case NodeKind.RETURN: return "RETURN";
|
|
||||||
case NodeKind.SUPER: return "SUPER";
|
|
||||||
case NodeKind.SWITCH: return "SWITCH";
|
|
||||||
case NodeKind.THIS: return "THIS";
|
|
||||||
case NodeKind.THROW: return "THROW";
|
|
||||||
case NodeKind.TRUE: return "TRUE";
|
|
||||||
case NodeKind.TRY: return "TRY";
|
|
||||||
case NodeKind.VARIABLE: return "VARIABLE";
|
|
||||||
case NodeKind.VARIABLEDECLARATION: return "VARIABLEDECLARATION";
|
|
||||||
case NodeKind.WHILE: return "WHILE";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
export class TypeNode extends Node {
|
export class TypeNode extends Node {
|
||||||
@ -416,18 +364,6 @@ export const enum LiteralKind {
|
|||||||
OBJECT
|
OBJECT
|
||||||
}
|
}
|
||||||
|
|
||||||
export function literalKindToString(kind: LiteralKind): string {
|
|
||||||
switch (kind) {
|
|
||||||
case LiteralKind.FLOAT: return "FLOAT";
|
|
||||||
case LiteralKind.INTEGER: return "INTEGER";
|
|
||||||
case LiteralKind.STRING: return "STRING";
|
|
||||||
case LiteralKind.REGEXP: return "REGEXP";
|
|
||||||
case LiteralKind.ARRAY: return "ARRAY";
|
|
||||||
case LiteralKind.OBJECT: return "OBJECT";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class LiteralExpression extends Expression {
|
export abstract class LiteralExpression extends Expression {
|
||||||
kind = NodeKind.LITERAL;
|
kind = NodeKind.LITERAL;
|
||||||
literalKind: LiteralKind;
|
literalKind: LiteralKind;
|
||||||
@ -840,24 +776,6 @@ export enum ModifierKind {
|
|||||||
SET
|
SET
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifierKindToString(kind: ModifierKind): string {
|
|
||||||
switch (kind) {
|
|
||||||
case ModifierKind.ASYNC: return "ASYNC";
|
|
||||||
case ModifierKind.CONST: return "CONST";
|
|
||||||
case ModifierKind.DECLARE: return "DECLARE";
|
|
||||||
case ModifierKind.EXPORT: return "EXPORT";
|
|
||||||
case ModifierKind.IMPORT: return "IMPORT";
|
|
||||||
case ModifierKind.STATIC: return "STATIC";
|
|
||||||
case ModifierKind.ABSTRACT: return "ABSTRACT";
|
|
||||||
case ModifierKind.PUBLIC: return "PUBLIC";
|
|
||||||
case ModifierKind.PRIVATE: return "PRIVATE";
|
|
||||||
case ModifierKind.PROTECTED: return "PROTECTED";
|
|
||||||
case ModifierKind.GET: return "GET";
|
|
||||||
case ModifierKind.SET: return "SET";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class Statement extends Node {
|
export abstract class Statement extends Node {
|
||||||
|
|
||||||
static createBlock(statements: Statement[], range: Range): BlockStatement {
|
static createBlock(statements: Statement[], range: Range): BlockStatement {
|
||||||
@ -943,6 +861,7 @@ export abstract class Statement extends Node {
|
|||||||
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 ? resolvePath(normalizePath(path.value), range.source.normalizedPath) : null;
|
stmt.normalizedPath = path ? resolvePath(normalizePath(path.value), range.source.normalizedPath) : null;
|
||||||
|
stmt.internalPath = stmt.normalizedPath ? mangleInternalPath(stmt.normalizedPath) : null;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,6 +903,7 @@ export abstract class Statement extends Node {
|
|||||||
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.value), range.source.normalizedPath);
|
stmt.normalizedPath = resolvePath(normalizePath(path.value), range.source.normalizedPath);
|
||||||
|
stmt.internalPath = mangleInternalPath(stmt.normalizedPath);
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,7 +915,7 @@ export abstract class Statement extends Node {
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createInterface(modifiers: Modifier[], extendsType: TypeNode | null, members: Statement[], range: Range): InterfaceDeclaration {
|
static createInterface(modifiers: Modifier[], extendsType: TypeNode | null, members: DeclarationStatement[], range: Range): InterfaceDeclaration {
|
||||||
const stmt: InterfaceDeclaration = new InterfaceDeclaration();
|
const stmt: InterfaceDeclaration = new InterfaceDeclaration();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -1164,6 +1084,7 @@ export class Source extends Node {
|
|||||||
parent = null;
|
parent = null;
|
||||||
path: string;
|
path: string;
|
||||||
normalizedPath: string;
|
normalizedPath: string;
|
||||||
|
internalPath: string;
|
||||||
statements: Statement[];
|
statements: Statement[];
|
||||||
|
|
||||||
text: string;
|
text: string;
|
||||||
@ -1174,6 +1095,7 @@ export class Source extends Node {
|
|||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.normalizedPath = normalizePath(path, true);
|
this.normalizedPath = normalizePath(path, true);
|
||||||
|
this.internalPath = mangleInternalPath(this.normalizedPath);
|
||||||
this.statements = new Array();
|
this.statements = new Array();
|
||||||
this.range = new Range(this, 0, text.length);
|
this.range = new Range(this, 0, text.length);
|
||||||
this.text = text;
|
this.text = text;
|
||||||
@ -1199,14 +1121,15 @@ export abstract class DeclarationStatement extends Statement {
|
|||||||
|
|
||||||
identifier: IdentifierExpression;
|
identifier: IdentifierExpression;
|
||||||
modifiers: Modifier[] | null;
|
modifiers: Modifier[] | null;
|
||||||
private _cachedInternalName: string | null = null;
|
|
||||||
globalExportName: string | null = null;
|
|
||||||
|
|
||||||
get internalName(): string {
|
protected _cachedInternalName: string | null = null;
|
||||||
if (this._cachedInternalName == null)
|
|
||||||
this._cachedInternalName = mangleInternalName(this);
|
get internalName(): string { return this._cachedInternalName === null ? this._cachedInternalName = mangleInternalName(this) : this._cachedInternalName; }
|
||||||
return this._cachedInternalName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export abstract class VariableLikeDeclarationStatement extends DeclarationStatement {
|
||||||
|
type: TypeNode | null;
|
||||||
|
initializer: Expression | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BlockStatement extends Statement {
|
export class BlockStatement extends Statement {
|
||||||
@ -1250,6 +1173,16 @@ export class ClassDeclaration extends DeclarationStatement {
|
|||||||
members: DeclarationStatement[];
|
members: DeclarationStatement[];
|
||||||
decorators: DecoratorStatement[];
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
|
get internalName(): string {
|
||||||
|
if (this._cachedInternalName !== null)
|
||||||
|
return this._cachedInternalName;
|
||||||
|
const globalDecorator: DecoratorStatement | null = getDecoratorByName("global", this.decorators);
|
||||||
|
if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
|
||||||
|
return this._cachedInternalName = this.identifier.name;
|
||||||
|
else
|
||||||
|
return this._cachedInternalName = mangleInternalName(this);
|
||||||
|
}
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
@ -1429,6 +1362,7 @@ export class ExportStatement extends Statement {
|
|||||||
members: ExportMember[];
|
members: ExportMember[];
|
||||||
path: StringLiteralExpression | null;
|
path: StringLiteralExpression | null;
|
||||||
normalizedPath: string | null;
|
normalizedPath: string | null;
|
||||||
|
internalPath: string | null;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -1461,11 +1395,9 @@ export class ExpressionStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FieldDeclaration extends DeclarationStatement {
|
export class FieldDeclaration extends VariableLikeDeclarationStatement {
|
||||||
|
|
||||||
kind = NodeKind.FIELD;
|
kind = NodeKind.FIELD;
|
||||||
type: TypeNode | null;
|
|
||||||
initializer: Expression | null;
|
|
||||||
decorators: DecoratorStatement[];
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
@ -1527,6 +1459,16 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
statements: Statement[] | null;
|
statements: Statement[] | null;
|
||||||
decorators: DecoratorStatement[];
|
decorators: DecoratorStatement[];
|
||||||
|
|
||||||
|
get internalName(): string {
|
||||||
|
if (this._cachedInternalName !== null)
|
||||||
|
return this._cachedInternalName;
|
||||||
|
const globalDecorator: DecoratorStatement | null = getDecoratorByName("global", this.decorators);
|
||||||
|
if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
|
||||||
|
return this._cachedInternalName = this.identifier.name;
|
||||||
|
else
|
||||||
|
return this._cachedInternalName = mangleInternalName(this);
|
||||||
|
}
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
for (i = 0, k = this.decorators.length; i < k; ++i) {
|
||||||
@ -1625,6 +1567,7 @@ export class ImportStatement extends Statement {
|
|||||||
declarations: ImportDeclaration[];
|
declarations: ImportDeclaration[];
|
||||||
path: StringLiteralExpression;
|
path: StringLiteralExpression;
|
||||||
normalizedPath: string;
|
normalizedPath: string;
|
||||||
|
internalPath: string;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("import {\n");
|
sb.push("import {\n");
|
||||||
@ -1638,12 +1581,9 @@ export class ImportStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InterfaceDeclaration extends DeclarationStatement {
|
export class InterfaceDeclaration extends ClassDeclaration {
|
||||||
|
|
||||||
kind = NodeKind.INTERFACE;
|
kind = NodeKind.INTERFACE;
|
||||||
typeParameters: TypeParameter[];
|
|
||||||
extendsType: TypeNode | null;
|
|
||||||
members: Statement[];
|
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -1872,12 +1812,10 @@ export class TryStatement extends Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VariableDeclaration extends DeclarationStatement {
|
export class VariableDeclaration extends VariableLikeDeclarationStatement {
|
||||||
|
|
||||||
kind = NodeKind.VARIABLEDECLARATION;
|
kind = NodeKind.VARIABLEDECLARATION;
|
||||||
modifiers = null;
|
modifiers = null;
|
||||||
type: TypeNode | null;
|
|
||||||
initializer: Expression | null;
|
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
this.identifier.serialize(sb);
|
this.identifier.serialize(sb);
|
||||||
@ -1940,21 +1878,53 @@ export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): b
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDecoratorByName(name: string, decorators: DecoratorStatement[]): DecoratorStatement | null {
|
||||||
|
for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) {
|
||||||
|
const decorator: DecoratorStatement = decorators[i];
|
||||||
|
const expression: Expression = decorator.expression;
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).name == name)
|
||||||
|
return decorator;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function serialize(node: Node, indent: i32 = 0): string {
|
export function serialize(node: Node, indent: i32 = 0): string {
|
||||||
const sb: string[] = new Array(); // shared builder could grow too much
|
const sb: string[] = new Array(); // shared builder could grow too much
|
||||||
node.serialize(sb);
|
node.serialize(sb);
|
||||||
return sb.join("");
|
return sb.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mangleInternalPath(path: string): string {
|
||||||
|
if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH)
|
||||||
|
path = path.replace("/", PATH_DELIMITER);
|
||||||
|
if (PARENT_SUBST != "..")
|
||||||
|
path = path.replace("..", PARENT_SUBST);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
export function mangleInternalName(declaration: DeclarationStatement): string {
|
export function mangleInternalName(declaration: DeclarationStatement): string {
|
||||||
let name: string = declaration.identifier.name;
|
let name: string = declaration.identifier.name;
|
||||||
|
let modifiers: Modifier[] | null;
|
||||||
|
if (declaration.kind == NodeKind.METHOD && (modifiers = declaration.modifiers)) {
|
||||||
|
for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) {
|
||||||
|
const modifier: Modifier = modifiers[i];
|
||||||
|
if (modifier.modifierKind == ModifierKind.GET) {
|
||||||
|
name = GETTER_PREFIX + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (modifier.modifierKind == ModifierKind.SET) {
|
||||||
|
name = SETTER_PREFIX + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!declaration.parent)
|
if (!declaration.parent)
|
||||||
return name;
|
return name;
|
||||||
if (declaration.parent.kind == NodeKind.CLASS)
|
if (declaration.parent.kind == NodeKind.CLASS)
|
||||||
return (<ClassDeclaration>declaration.parent).internalName + (hasModifier(ModifierKind.STATIC, declaration.modifiers) ? "." : "#") + name;
|
return (<ClassDeclaration>declaration.parent).internalName + (hasModifier(ModifierKind.STATIC, declaration.modifiers) ? STATIC_DELIMITER : INSTANCE_DELIMITER) + name;
|
||||||
if (declaration.parent.kind == NodeKind.NAMESPACE || declaration.parent.kind == NodeKind.ENUM)
|
if (declaration.parent.kind == NodeKind.NAMESPACE || declaration.parent.kind == NodeKind.ENUM)
|
||||||
return (<DeclarationStatement>declaration.parent).internalName + "." + name;
|
return (<DeclarationStatement>declaration.parent).internalName + STATIC_DELIMITER + name;
|
||||||
return declaration.range.source.normalizedPath + "/" + name;
|
return declaration.range.source.internalPath + PATH_DELIMITER + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function builderEndsWith(sb: string[], code: CharCode): bool {
|
function builderEndsWith(sb: string[], code: CharCode): bool {
|
||||||
|
726
src/compiler.ts
726
src/compiler.ts
File diff suppressed because it is too large
Load Diff
8
src/constants.ts
Normal file
8
src/constants.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// internal naming scheme
|
||||||
|
|
||||||
|
export const PATH_DELIMITER: string = "/";
|
||||||
|
export const PARENT_SUBST: string = "..";
|
||||||
|
export const GETTER_PREFIX: string = "get:";
|
||||||
|
export const SETTER_PREFIX: string = "set:";
|
||||||
|
export const INSTANCE_DELIMITER: string = "#";
|
||||||
|
export const STATIC_DELIMITER: string = ".";
|
@ -3,6 +3,7 @@
|
|||||||
export enum DiagnosticCode {
|
export enum DiagnosticCode {
|
||||||
Conversion_from_type_0_to_1_requires_an_explicit_cast = 100,
|
Conversion_from_type_0_to_1_requires_an_explicit_cast = 100,
|
||||||
Basic_type_0_cannot_be_nullable = 101,
|
Basic_type_0_cannot_be_nullable = 101,
|
||||||
|
Operation_not_supported = 102,
|
||||||
Unterminated_string_literal = 1002,
|
Unterminated_string_literal = 1002,
|
||||||
Identifier_expected = 1003,
|
Identifier_expected = 1003,
|
||||||
_0_expected = 1005,
|
_0_expected = 1005,
|
||||||
@ -32,6 +33,7 @@ export enum DiagnosticCode {
|
|||||||
Unexpected_end_of_text = 1126,
|
Unexpected_end_of_text = 1126,
|
||||||
Invalid_character = 1127,
|
Invalid_character = 1127,
|
||||||
_case_or_default_expected = 1130,
|
_case_or_default_expected = 1130,
|
||||||
|
Type_argument_expected = 1140,
|
||||||
String_literal_expected = 1141,
|
String_literal_expected = 1141,
|
||||||
Line_break_not_permitted_here = 1142,
|
Line_break_not_permitted_here = 1142,
|
||||||
Declaration_expected = 1146,
|
Declaration_expected = 1146,
|
||||||
@ -50,8 +52,10 @@ export enum DiagnosticCode {
|
|||||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||||
_this_cannot_be_referenced_in_current_location = 2332,
|
_this_cannot_be_referenced_in_current_location = 2332,
|
||||||
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
||||||
|
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
|
||||||
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
||||||
Duplicate_function_implementation = 2393,
|
Duplicate_function_implementation = 2393,
|
||||||
|
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
|
||||||
Expected_0_type_arguments_but_got_1 = 2558,
|
Expected_0_type_arguments_but_got_1 = 2558,
|
||||||
File_0_not_found = 6054
|
File_0_not_found = 6054
|
||||||
}
|
}
|
||||||
@ -60,6 +64,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
switch (code) {
|
switch (code) {
|
||||||
case 100: return "Conversion from type '{0}' to '{1}' requires an explicit cast.";
|
case 100: return "Conversion from type '{0}' to '{1}' requires an explicit cast.";
|
||||||
case 101: return "Basic type '{0}' cannot be nullable.";
|
case 101: return "Basic type '{0}' cannot be nullable.";
|
||||||
|
case 102: return "Operation not supported.";
|
||||||
case 1002: return "Unterminated string literal.";
|
case 1002: return "Unterminated string literal.";
|
||||||
case 1003: return "Identifier expected.";
|
case 1003: return "Identifier expected.";
|
||||||
case 1005: return "'{0}' expected.";
|
case 1005: return "'{0}' expected.";
|
||||||
@ -89,6 +94,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 1126: return "Unexpected end of text.";
|
case 1126: return "Unexpected end of text.";
|
||||||
case 1127: return "Invalid character.";
|
case 1127: return "Invalid character.";
|
||||||
case 1130: return "'case' or 'default' expected.";
|
case 1130: return "'case' or 'default' expected.";
|
||||||
|
case 1140: return "Type argument expected.";
|
||||||
case 1141: return "String literal expected.";
|
case 1141: return "String literal expected.";
|
||||||
case 1142: return "Line break not permitted here.";
|
case 1142: return "Line break not permitted here.";
|
||||||
case 1146: return "Declaration expected.";
|
case 1146: return "Declaration expected.";
|
||||||
@ -107,8 +113,10 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||||
case 2332: return "'this' cannot be referenced in current location.";
|
case 2332: return "'this' cannot be referenced in current location.";
|
||||||
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
||||||
|
case 2364: return "The left-hand side of an assignment expression 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.";
|
||||||
case 2393: return "Duplicate function implementation.";
|
case 2393: return "Duplicate function implementation.";
|
||||||
|
case 2541: return "The target of an assignment must be a variable or a property access.";
|
||||||
case 2558: return "Expected {0} type arguments, but got {1}.";
|
case 2558: return "Expected {0} type arguments, but got {1}.";
|
||||||
case 6054: return "File '{0}' not found.";
|
case 6054: return "File '{0}' not found.";
|
||||||
default: return "";
|
default: return "";
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Conversion from type '{0}' to '{1}' requires an explicit cast.": 100,
|
"Conversion from type '{0}' to '{1}' requires an explicit cast.": 100,
|
||||||
"Basic type '{0}' cannot be nullable.": 101,
|
"Basic type '{0}' cannot be nullable.": 101,
|
||||||
|
"Operation not supported.": 102,
|
||||||
|
|
||||||
"Unterminated string literal.": 1002,
|
"Unterminated string literal.": 1002,
|
||||||
"Identifier expected.": 1003,
|
"Identifier expected.": 1003,
|
||||||
@ -31,6 +32,7 @@
|
|||||||
"Unexpected end of text.": 1126,
|
"Unexpected end of text.": 1126,
|
||||||
"Invalid character.": 1127,
|
"Invalid character.": 1127,
|
||||||
"'case' or 'default' expected.": 1130,
|
"'case' or 'default' expected.": 1130,
|
||||||
|
"Type argument expected.": 1140,
|
||||||
"String literal expected.": 1141,
|
"String literal expected.": 1141,
|
||||||
"Line break not permitted here.": 1142,
|
"Line break not permitted here.": 1142,
|
||||||
"Declaration expected.": 1146,
|
"Declaration expected.": 1146,
|
||||||
@ -50,8 +52,10 @@
|
|||||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||||
"'this' cannot be referenced in current location.": 2332,
|
"'this' cannot be referenced in current location.": 2332,
|
||||||
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
||||||
|
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
|
||||||
"Function implementation is missing or not immediately following the declaration.": 2391,
|
"Function implementation is missing or not immediately following the declaration.": 2391,
|
||||||
"Duplicate function implementation.": 2393,
|
"Duplicate function implementation.": 2393,
|
||||||
|
"The target of an assignment must be a variable or a property access.": 2541,
|
||||||
"Expected {0} type arguments, but got {1}.": 2558,
|
"Expected {0} type arguments, but got {1}.": 2558,
|
||||||
|
|
||||||
"File '{0}' not found.": 6054
|
"File '{0}' not found.": 6054
|
||||||
|
@ -462,13 +462,13 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
// Identifier ('extends' Type)?
|
// Identifier ('extends' Type)?
|
||||||
if (tn.next() == Token.IDENTIFIER) {
|
if (tn.next() == Token.IDENTIFIER) {
|
||||||
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
||||||
let extendsName: TypeNode | null = null;
|
let extendsType: TypeNode | null = null;
|
||||||
if (tn.skip(Token.EXTENDS)) {
|
if (tn.skip(Token.EXTENDS)) {
|
||||||
extendsName = this.parseType(tn);
|
extendsType = this.parseType(tn);
|
||||||
if (!extendsName)
|
if (!extendsType)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Statement.createTypeParameter(identifier, extendsName, Range.join(identifier.range, tn.range()));
|
return Statement.createTypeParameter(identifier, extendsType, Range.join(identifier.range, tn.range()));
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode.Identifier_expected, tn.range());
|
this.error(DiagnosticCode.Identifier_expected, tn.range());
|
||||||
return null;
|
return null;
|
||||||
|
751
src/program.ts
751
src/program.ts
@ -1,15 +1,27 @@
|
|||||||
import { Target } from "./compiler";
|
import { Target } from "./compiler";
|
||||||
|
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { Type } from "./types";
|
import { Type, typesToString } from "./types";
|
||||||
|
import { I64 } from "./util";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
ModifierKind,
|
ModifierKind,
|
||||||
Node,
|
Node,
|
||||||
NodeKind,
|
NodeKind,
|
||||||
Source,
|
Source,
|
||||||
|
Range,
|
||||||
|
|
||||||
|
TypeNode,
|
||||||
|
Expression,
|
||||||
|
IdentifierExpression,
|
||||||
|
LiteralExpression,
|
||||||
|
LiteralKind,
|
||||||
|
PropertyAccessExpression,
|
||||||
|
StringLiteralExpression,
|
||||||
|
|
||||||
ClassDeclaration,
|
ClassDeclaration,
|
||||||
DeclarationStatement,
|
DeclarationStatement,
|
||||||
|
DecoratorStatement,
|
||||||
EnumDeclaration,
|
EnumDeclaration,
|
||||||
EnumValueDeclaration,
|
EnumValueDeclaration,
|
||||||
ExportMember,
|
ExportMember,
|
||||||
@ -20,8 +32,11 @@ import {
|
|||||||
ImportStatement,
|
ImportStatement,
|
||||||
InterfaceDeclaration,
|
InterfaceDeclaration,
|
||||||
MethodDeclaration,
|
MethodDeclaration,
|
||||||
|
Modifier,
|
||||||
NamespaceDeclaration,
|
NamespaceDeclaration,
|
||||||
Statement,
|
Statement,
|
||||||
|
TypeParameter,
|
||||||
|
VariableLikeDeclarationStatement,
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
VariableStatement,
|
VariableStatement,
|
||||||
|
|
||||||
@ -41,29 +56,32 @@ class QueuedImport {
|
|||||||
declaration: ImportDeclaration;
|
declaration: ImportDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typesStub: Map<string,Type> = new Map();
|
const reusableTypesStub: Map<string,Type> = new Map();
|
||||||
|
|
||||||
export class Program extends DiagnosticEmitter {
|
export class Program extends DiagnosticEmitter {
|
||||||
|
|
||||||
|
/** Array of source files. */
|
||||||
sources: Source[];
|
sources: Source[];
|
||||||
|
/** Diagnostic offset used where sequentially obtaining the next diagnostic. */
|
||||||
diagnosticsOffset: i32 = 0;
|
diagnosticsOffset: i32 = 0;
|
||||||
target: Target = Target.WASM32;
|
/** WASM target. */
|
||||||
|
target: Target = Target.WASM32; // set on initialization
|
||||||
/** Map of internal names to declarations. */
|
/** Elements by internal name. */
|
||||||
names: Map<string,DeclarationStatement> = new Map();
|
elements: Map<string,Element> = new Map();
|
||||||
/** Separate map of internal type names to declarations. */
|
/** Types by internal name. */
|
||||||
types: Map<string,Type> = typesStub;
|
types: Map<string,Type> = reusableTypesStub;
|
||||||
/** Separate map of internal export names to declarations. */
|
/** Exports of individual files by internal name. Not global exports. */
|
||||||
exports: Map<string,DeclarationStatement> = new Map(); // not global exports
|
exports: Map<string,Element> = new Map();
|
||||||
|
|
||||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||||
super(diagnostics);
|
super(diagnostics);
|
||||||
this.sources = new Array();
|
this.sources = new Array();
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(target: Target): void {
|
/** Initializes the program and its elements prior to compilation. */
|
||||||
|
initialize(target: Target = Target.WASM32): void {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.types = new Map([
|
this.types = new Map([ // replaces typesStub
|
||||||
["i8", Type.i8],
|
["i8", Type.i8],
|
||||||
["i16", Type.i16],
|
["i16", Type.i16],
|
||||||
["i32", Type.i32],
|
["i32", Type.i32],
|
||||||
@ -127,9 +145,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// at this point queued exports should be resolvable
|
// at this point queued exports should be resolvable
|
||||||
// export { add }
|
for (let [exportName, queuedExport] of queuedExports) { // all file-level exports
|
||||||
// export { sub } from "./other"
|
|
||||||
for (let [exportName, queuedExport] of queuedExports) {
|
|
||||||
if (queuedExport.isForeign) {
|
if (queuedExport.isForeign) {
|
||||||
const seen: Set<QueuedExport> = new Set();
|
const seen: Set<QueuedExport> = new Set();
|
||||||
while (queuedExports.has(queuedExport.referencedName)) {
|
while (queuedExports.has(queuedExport.referencedName)) {
|
||||||
@ -139,18 +155,20 @@ export class Program extends DiagnosticEmitter {
|
|||||||
seen.add(queuedExport);
|
seen.add(queuedExport);
|
||||||
}
|
}
|
||||||
if (this.exports.has(queuedExport.referencedName)) {
|
if (this.exports.has(queuedExport.referencedName)) {
|
||||||
const declaration: DeclarationStatement = <DeclarationStatement>this.exports.get(queuedExport.referencedName);
|
const element: Element = <Element>this.exports.get(queuedExport.referencedName);
|
||||||
this.addExport(exportName, declaration);
|
if (!this.exports.has(exportName))
|
||||||
|
this.exports.set(exportName, element);
|
||||||
if (queuedExport.member.range.source.isEntry)
|
if (queuedExport.member.range.source.isEntry)
|
||||||
declaration.globalExportName = queuedExport.member.externalIdentifier.name;
|
element.globalExportName = queuedExport.member.externalIdentifier.name;
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
||||||
} else /* local */ {
|
} else /* local */ {
|
||||||
if (this.names.has(queuedExport.referencedName)) {
|
if (this.elements.has(queuedExport.referencedName)) {
|
||||||
const declaration: DeclarationStatement = <DeclarationStatement>this.names.get(queuedExport.referencedName);
|
const element: Element = <Element>this.elements.get(queuedExport.referencedName);
|
||||||
this.addExport(exportName, declaration);
|
if (!this.exports.has(exportName))
|
||||||
|
this.exports.set(exportName, element);
|
||||||
if (queuedExport.member.range.source.isEntry)
|
if (queuedExport.member.range.source.isEntry)
|
||||||
declaration.globalExportName = queuedExport.member.externalIdentifier.name;
|
element.globalExportName = queuedExport.member.externalIdentifier.name;
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
||||||
}
|
}
|
||||||
@ -170,13 +188,11 @@ export class Program extends DiagnosticEmitter {
|
|||||||
seen.add(queuedExport);
|
seen.add(queuedExport);
|
||||||
}
|
}
|
||||||
if (this.exports.has(importName)) {
|
if (this.exports.has(importName)) {
|
||||||
if (this.names.has(internalName))
|
if (this.elements.has(internalName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, queuedImport.declaration.identifier.range, internalName);
|
this.error(DiagnosticCode.Duplicate_identifier_0, queuedImport.declaration.identifier.range, internalName);
|
||||||
else {
|
else {
|
||||||
const declaration: DeclarationStatement = <DeclarationStatement>this.exports.get(importName);
|
const element: Element = <Element>this.exports.get(importName);
|
||||||
this.names.set(internalName, declaration);
|
this.elements.set(internalName, element);
|
||||||
// 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, queuedImport.declaration.externalIdentifier.range, importName);
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedImport.declaration.externalIdentifier.range, importName);
|
||||||
@ -185,20 +201,28 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
private initializeClass(declaration: ClassDeclaration): void {
|
private initializeClass(declaration: ClassDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const template: ClassTemplate = new ClassTemplate(this, internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
const members: DeclarationStatement[] = declaration.members;
|
else
|
||||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
this.elements.set(internalName, template);
|
||||||
const statement: Statement = members[j];
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||||
switch (statement.kind) {
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, template);
|
||||||
|
}
|
||||||
|
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||||
|
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||||
|
const memberDeclaration: DeclarationStatement = memberDeclarations[j];
|
||||||
|
switch (memberDeclaration.kind) {
|
||||||
|
|
||||||
case NodeKind.FIELD:
|
case NodeKind.FIELD:
|
||||||
this.initializeField(<FieldDeclaration>statement);
|
this.initializeField(<FieldDeclaration>memberDeclaration, template);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.METHOD:
|
case NodeKind.METHOD:
|
||||||
this.initializeMethod(<MethodDeclaration>statement);
|
this.initializeMethod(<MethodDeclaration>memberDeclaration, template);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -207,42 +231,103 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeField(declaration: FieldDeclaration): void {
|
private initializeField(declaration: FieldDeclaration, template: ClassTemplate): void {
|
||||||
this.addName(declaration.internalName, declaration);
|
const name: string = declaration.identifier.name;
|
||||||
|
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||||
|
const internalName: string = declaration.internalName;
|
||||||
|
if (template.members.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
const global: Global = new Global(this, internalName, declaration, null);
|
||||||
|
template.members.set(name, global);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (template.fieldDeclarations.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||||
|
else
|
||||||
|
template.fieldDeclarations.set(name, declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeMethod(declaration: MethodDeclaration, template: ClassTemplate): void {
|
||||||
|
let name: string = declaration.identifier.name;
|
||||||
|
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||||
|
const internalName: string = declaration.internalName;
|
||||||
|
if (template.members.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
const func: FunctionTemplate = new FunctionTemplate(this, internalName, declaration);
|
||||||
|
let modifiers: Modifier[] | null;
|
||||||
|
if (modifiers = declaration.modifiers) {
|
||||||
|
for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) {
|
||||||
|
const modifier: Modifier = modifiers[i];
|
||||||
|
if (modifier.modifierKind == ModifierKind.GET) {
|
||||||
|
name = GETTER_PREFIX + name;
|
||||||
|
break;
|
||||||
|
} else if (modifier.modifierKind == ModifierKind.SET) {
|
||||||
|
name = SETTER_PREFIX + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template.members.set(name, func);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (template.methodDeclarations.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||||
|
else
|
||||||
|
template.methodDeclarations.set(name, declaration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeEnum(declaration: EnumDeclaration): void {
|
private initializeEnum(declaration: EnumDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const enm: Enum = new Enum(this, internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
this.elements.set(internalName, enm);
|
||||||
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||||
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, enm);
|
||||||
|
}
|
||||||
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], enm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeEnumValue(declaration: EnumValueDeclaration): void {
|
private initializeEnumValue(declaration: EnumValueDeclaration, enm: Enum): void {
|
||||||
this.addName(declaration.internalName, declaration);
|
const name: string = declaration.identifier.name;
|
||||||
|
const internalName: string = declaration.internalName;
|
||||||
|
if (enm.members.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
const value: EnumValue = new EnumValue(enm, this, internalName, declaration);
|
||||||
|
enm.members.set(name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
||||||
const members: ExportMember[] = statement.members;
|
const members: ExportMember[] = statement.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.initializeExport(members[i], statement.normalizedPath, queuedExports);
|
this.initializeExport(members[i], statement.internalPath, queuedExports);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeExport(member: ExportMember, normalizedPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
||||||
const exportName: string = member.range.source.normalizedPath + "/" + member.externalIdentifier.name;
|
const exportName: string = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
||||||
if (queuedExports.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 queuedExport: QueuedExport = new QueuedExport();
|
const queuedExport: QueuedExport = new QueuedExport();
|
||||||
if (normalizedPath == null) {
|
if (internalPath == null) {
|
||||||
queuedExport.isForeign = false;
|
queuedExport.isForeign = false;
|
||||||
queuedExport.referencedName = member.range.source.normalizedPath + "/" + member.identifier.name;
|
queuedExport.referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name;
|
||||||
} else {
|
} else {
|
||||||
queuedExport.isForeign = true;
|
queuedExport.isForeign = true;
|
||||||
queuedExport.referencedName = (<string>normalizedPath) + "/" + member.identifier.name;
|
queuedExport.referencedName = (<string>internalPath) + PATH_DELIMITER + member.identifier.name;
|
||||||
}
|
}
|
||||||
queuedExport.member = member;
|
queuedExport.member = member;
|
||||||
queuedExports.set(exportName, queuedExport);
|
queuedExports.set(exportName, queuedExport);
|
||||||
@ -251,21 +336,30 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
private initializeFunction(declaration: FunctionDeclaration): void {
|
private initializeFunction(declaration: FunctionDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const template: FunctionTemplate = new FunctionTemplate(this, internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
this.elements.set(internalName, template);
|
||||||
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||||
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, template);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||||
const members: ImportDeclaration[] = statement.declarations;
|
const members: ImportDeclaration[] = statement.declarations;
|
||||||
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, statement.normalizedPath, queuedExports, queuedImports);
|
this.initializeImport(declaration, statement.internalPath, queuedExports, queuedImports);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeImport(declaration: ImportDeclaration, normalizedPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||||
const importName: string = normalizedPath + "/" + declaration.externalIdentifier.name;
|
const importName: string = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name;
|
||||||
let resolvedImportName: string = importName;
|
let resolvedImportName: string = importName;
|
||||||
const seen: Set<QueuedExport> = new Set();
|
const seen: Set<QueuedExport> = new Set();
|
||||||
while (queuedExports.has(resolvedImportName)) {
|
while (queuedExports.has(resolvedImportName)) {
|
||||||
@ -277,10 +371,10 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
||||||
if (this.names.has(internalName))
|
if (this.elements.has(internalName))
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
else
|
else
|
||||||
this.names.set(internalName, <DeclarationStatement>this.exports.get(resolvedImportName));
|
this.elements.set(internalName, <Element>this.exports.get(resolvedImportName));
|
||||||
} else { // points to yet unresolved export
|
} else { // points to yet unresolved export
|
||||||
const queuedImport: QueuedImport = new QueuedImport();
|
const queuedImport: QueuedImport = new QueuedImport();
|
||||||
queuedImport.internalName = internalName;
|
queuedImport.internalName = internalName;
|
||||||
@ -292,20 +386,28 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
private initializeInterface(declaration: InterfaceDeclaration): void {
|
private initializeInterface(declaration: InterfaceDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const template: InterfaceTemplate = new InterfaceTemplate(this, internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
const members: Statement[] = declaration.members;
|
else
|
||||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
this.elements.set(internalName, template);
|
||||||
const statement: Statement = members[j];
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||||
switch (statement.kind) {
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, template);
|
||||||
|
}
|
||||||
|
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||||
|
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||||
|
const memberDeclaration: DeclarationStatement = memberDeclarations[j];
|
||||||
|
switch (memberDeclaration.kind) {
|
||||||
|
|
||||||
case NodeKind.FIELD:
|
case NodeKind.FIELD:
|
||||||
this.initializeField(<FieldDeclaration>statement);
|
this.initializeField(<FieldDeclaration>memberDeclaration, template);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.METHOD:
|
case NodeKind.METHOD:
|
||||||
this.initializeMethod(<MethodDeclaration>statement);
|
this.initializeMethod(<MethodDeclaration>memberDeclaration, template);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -314,15 +416,20 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeMethod(declaration: MethodDeclaration): void {
|
|
||||||
this.addName(declaration.internalName, declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const ns: Namespace = new Namespace(this, internalName, declaration);
|
||||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else {
|
||||||
|
this.elements.set(internalName, ns);
|
||||||
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||||
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
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];
|
||||||
@ -364,26 +471,484 @@ export class Program extends DiagnosticEmitter {
|
|||||||
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
||||||
const declaration: VariableDeclaration = declarations[i];
|
const declaration: VariableDeclaration = declarations[i];
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
this.addName(internalName, declaration);
|
const global: Global = new Global(this, internalName, declaration, null);
|
||||||
if (isExport)
|
if (this.elements.has(internalName))
|
||||||
this.addExport(/* same as */internalName, declaration);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private addName(internalName: string, declaration: DeclarationStatement): void {
|
|
||||||
if (this.names.has(internalName))
|
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); // recoverable
|
|
||||||
else
|
|
||||||
this.names.set(internalName, declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private addExport(exportName: string, declaration: DeclarationStatement): void {
|
|
||||||
if (this.exports.has(exportName))
|
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, exportName); // recoverable
|
|
||||||
else {
|
else {
|
||||||
this.exports.set(exportName, declaration);
|
this.elements.set(internalName, global);
|
||||||
if (declaration.range.source.isEntry)
|
if (isExport) {
|
||||||
declaration.globalExportName = declaration.identifier.name;
|
if (this.exports.has(internalName))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
|
else
|
||||||
|
this.exports.set(internalName, global);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveType(node: TypeNode, contextualTypeArguments: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
||||||
|
|
||||||
|
// resolve parameters
|
||||||
|
const k: i32 = node.parameters.length;
|
||||||
|
const paramTypes: Type[] = new Array(k);
|
||||||
|
for (let i: i32 = 0; i < k; ++i) {
|
||||||
|
const paramType: Type | null = this.resolveType(node.parameters[i], contextualTypeArguments, reportNotFound);
|
||||||
|
if (!paramType)
|
||||||
|
return null;
|
||||||
|
paramTypes[i] = <Type>paramType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let globalName: string = node.identifier.name;
|
||||||
|
if (k) // can't be a placeholder if it has parameters
|
||||||
|
globalName += typesToString(paramTypes);
|
||||||
|
else if (contextualTypeArguments) {
|
||||||
|
const placeholderType: Type | null = <Type | null>contextualTypeArguments.get(globalName);
|
||||||
|
if (placeholderType)
|
||||||
|
return placeholderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type: Type | null;
|
||||||
|
|
||||||
|
// check file-global type
|
||||||
|
if (type = <Type | null>this.types.get(node.range.source.internalPath + PATH_DELIMITER + globalName))
|
||||||
|
return type;
|
||||||
|
|
||||||
|
// check program-global type
|
||||||
|
if (type = <Type | null>this.types.get(globalName))
|
||||||
|
return type;
|
||||||
|
|
||||||
|
if (reportNotFound)
|
||||||
|
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
|
||||||
|
const parameterCount: i32 = typeParameters.length;
|
||||||
|
const argumentCount: i32 = typeArgumentNodes.length;
|
||||||
|
if (parameterCount != argumentCount) {
|
||||||
|
if (argumentCount)
|
||||||
|
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join(typeArgumentNodes[0].range, typeArgumentNodes[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
|
||||||
|
else if (alternativeReportNode)
|
||||||
|
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, alternativeReportNode.range.atEnd, parameterCount.toString(10), "0");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const typeArguments: Type[] = new Array(parameterCount);
|
||||||
|
for (let i: i32 = 0; i < parameterCount; ++i) {
|
||||||
|
const type: Type | null = this.resolveType(typeArgumentNodes[i], contextualTypeArguments, true); // reports
|
||||||
|
if (!type)
|
||||||
|
return null;
|
||||||
|
// TODO: check extendsType
|
||||||
|
typeArguments[i] = type;
|
||||||
|
}
|
||||||
|
return typeArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveElement(expression: Expression, contextualFunction: FunctionInstance): Element | null {
|
||||||
|
|
||||||
|
// this
|
||||||
|
if (expression.kind == NodeKind.THIS) {
|
||||||
|
if (contextualFunction.instanceMethodOf)
|
||||||
|
return contextualFunction.instanceMethodOf.template;
|
||||||
|
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// local or global name
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||||
|
const name: string = (<IdentifierExpression>expression).name;
|
||||||
|
const local: Local | null = <Local | null>contextualFunction.locals.get(name);
|
||||||
|
if (local)
|
||||||
|
return local;
|
||||||
|
const fileGlobalElement: Element | null = <Element | null>this.elements.get(expression.range.source.internalPath + PATH_DELIMITER + name);
|
||||||
|
if (fileGlobalElement)
|
||||||
|
return fileGlobalElement;
|
||||||
|
const programGlobalElement: Element | null = <Element | null>this.elements.get(name);
|
||||||
|
if (programGlobalElement)
|
||||||
|
return programGlobalElement;
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// static or instance property (incl. enum values) or method
|
||||||
|
} else if (expression.kind == NodeKind.PROPERTYACCESS) {
|
||||||
|
const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction);
|
||||||
|
if (!target)
|
||||||
|
return null;
|
||||||
|
switch (target.kind) {
|
||||||
|
case ElementKind.CLASS:
|
||||||
|
case ElementKind.ENUM:
|
||||||
|
case ElementKind.NAMESPACE:
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkGlobalDecorator(decorators: DecoratorStatement[]): string | null {
|
||||||
|
for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) {
|
||||||
|
const decorator: DecoratorStatement = decorators[i];
|
||||||
|
const expression: Expression = decorator.expression;
|
||||||
|
const args: Expression[] = decorator.arguments;
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER && args.length <= 1 && (<IdentifierExpression>expression).name == "global") {
|
||||||
|
if (args.length) {
|
||||||
|
const firstArg: Expression = args[0];
|
||||||
|
if (firstArg.kind == NodeKind.LITERAL && (<LiteralExpression>firstArg).literalKind == LiteralKind.STRING)
|
||||||
|
return (<StringLiteralExpression>firstArg).value;
|
||||||
|
} else
|
||||||
|
return ""; // instead inherits declaration identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ElementKind {
|
||||||
|
CLASS,
|
||||||
|
CLASSINSTANCE,
|
||||||
|
ENUM,
|
||||||
|
ENUMVALUE,
|
||||||
|
FUNCTION,
|
||||||
|
FUNCTIONINSTANCE,
|
||||||
|
GLOBAL,
|
||||||
|
INTERFACE,
|
||||||
|
INTERFACEINSTANCE,
|
||||||
|
LOCAL,
|
||||||
|
NAMESPACE
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class Element {
|
||||||
|
|
||||||
|
kind: ElementKind;
|
||||||
|
program: Program;
|
||||||
|
internalName: string;
|
||||||
|
globalExportName: string | null = null;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string) {
|
||||||
|
this.program = program;
|
||||||
|
this.internalName = internalName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Enum extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.ENUM;
|
||||||
|
declaration: EnumDeclaration | null;
|
||||||
|
members: Map<string,EnumValue> = new Map();
|
||||||
|
compiled: bool = false;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: EnumDeclaration | null = null) {
|
||||||
|
super(program, internalName);
|
||||||
|
this.declaration = declaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||||
|
get isGlobalExport(): bool { return this.globalExportName != null; }
|
||||||
|
get isConstant(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are const */ true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EnumValue extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.ENUMVALUE;
|
||||||
|
declaration: EnumValueDeclaration | null;
|
||||||
|
enum: Enum;
|
||||||
|
hasConstantValue: bool = false;
|
||||||
|
constantValue: i32 = 0;
|
||||||
|
|
||||||
|
constructor(enm: Enum, program: Program, internalName: string, declaration: EnumValueDeclaration | null = null) {
|
||||||
|
super(program, internalName);
|
||||||
|
this.enum = enm;
|
||||||
|
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Global extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.GLOBAL;
|
||||||
|
declaration: VariableLikeDeclarationStatement | null;
|
||||||
|
type: Type | null;
|
||||||
|
hasConstantValue: bool = false;
|
||||||
|
constantIntegerValue: I64 = new I64(0, 0);
|
||||||
|
constantFloatValue: f64 = 0;
|
||||||
|
compiled: bool = false;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null, type: Type | null) {
|
||||||
|
super(program, internalName);
|
||||||
|
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||||
|
this.type = type; // resolved later if `null`
|
||||||
|
}
|
||||||
|
|
||||||
|
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||||
|
get isGlobalExport(): bool { return this.globalExportName != null; }
|
||||||
|
get isMutable(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Namespace extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.NAMESPACE;
|
||||||
|
declaration: NamespaceDeclaration | null;
|
||||||
|
members: Map<string,Element> = new Map();
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: NamespaceDeclaration | null) {
|
||||||
|
super(program, internalName);
|
||||||
|
this.declaration = declaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : false; }
|
||||||
|
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't exports */ false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Parameter {
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
type: Type;
|
||||||
|
|
||||||
|
constructor(name: string, type: Type) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Local extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.LOCAL;
|
||||||
|
index: i32;
|
||||||
|
type: Type;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, index: i32, type: Type) {
|
||||||
|
super(program, internalName);
|
||||||
|
this.index = index;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FunctionTemplate extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.FUNCTION;
|
||||||
|
declaration: FunctionDeclaration | null;
|
||||||
|
instances: Map<string,FunctionInstance>;
|
||||||
|
isGeneric: bool;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null) {
|
||||||
|
super(program, internalName);
|
||||||
|
this.declaration = declaration;
|
||||||
|
this.instances = new Map();
|
||||||
|
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // builtins set this
|
||||||
|
}
|
||||||
|
|
||||||
|
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||||
|
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't global exports */ false; }
|
||||||
|
get isGetter(): bool { return this.declaration ? hasModifier(ModifierKind.GET, this.declaration.modifiers) : /* internals aren't getters */ false; }
|
||||||
|
get isSetter(): bool { return this.declaration ? hasModifier(ModifierKind.SET, this.declaration.modifiers) : /* internals aren't setters */ false; }
|
||||||
|
|
||||||
|
instantiate(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): FunctionInstance | null {
|
||||||
|
const instanceKey: string = typesToString(typeArguments, "", "");
|
||||||
|
let instance: FunctionInstance | null = <FunctionInstance | null>this.instances.get(instanceKey);
|
||||||
|
if (instance)
|
||||||
|
return instance;
|
||||||
|
const declaration: FunctionDeclaration | null = this.declaration;
|
||||||
|
if (!declaration)
|
||||||
|
throw new Error("unexpected instantiation of internal function");
|
||||||
|
|
||||||
|
// override call specific contextual type arguments
|
||||||
|
let i: i32, k: i32 = typeArguments.length;
|
||||||
|
if (k) {
|
||||||
|
const inheritedTypeArguments: Map<string,Type> | null = contextualTypeArguments;
|
||||||
|
contextualTypeArguments = new Map();
|
||||||
|
if (inheritedTypeArguments)
|
||||||
|
for (let [name, type] of inheritedTypeArguments)
|
||||||
|
contextualTypeArguments.set(name, type);
|
||||||
|
for (i = 0; i < k; ++i)
|
||||||
|
contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve parameters
|
||||||
|
k = declaration.parameters.length;
|
||||||
|
const parameters: Parameter[] = new Array(k);
|
||||||
|
const parameterTypes: Type[] = new Array(k);
|
||||||
|
for (let i = 0; i < k; ++i) {
|
||||||
|
const typeNode: TypeNode | null = declaration.parameters[i].type;
|
||||||
|
if (typeNode) {
|
||||||
|
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
|
||||||
|
if (type) {
|
||||||
|
parameters[i] = new Parameter(declaration.parameters[i].identifier.name, type);
|
||||||
|
parameterTypes[i] = <Type>type;
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
|
return null; // TODO: infer type? (currently reported by parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve return type
|
||||||
|
const typeNode: TypeNode | null = declaration.returnType;
|
||||||
|
let returnType: Type;
|
||||||
|
if (typeNode) {
|
||||||
|
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
|
||||||
|
if (type)
|
||||||
|
returnType = <Type>type;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
|
return null; // TODO: infer type? (currently reported by parser)
|
||||||
|
|
||||||
|
let internalName: string = this.internalName;
|
||||||
|
if (instanceKey.length)
|
||||||
|
internalName += "<" + instanceKey + ">";
|
||||||
|
instance = new FunctionInstance(this, internalName, typeArguments, parameters, returnType, null); // TODO: class
|
||||||
|
this.instances.set(instanceKey, instance);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FunctionInstance extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.FUNCTIONINSTANCE;
|
||||||
|
template: FunctionTemplate;
|
||||||
|
typeArguments: Type[];
|
||||||
|
parameters: Parameter[];
|
||||||
|
returnType: Type;
|
||||||
|
instanceMethodOf: ClassInstance | null;
|
||||||
|
locals: Map<string,Local> = new Map();
|
||||||
|
additionalLocals: Type[] = [];
|
||||||
|
breakContext: string | null = null;
|
||||||
|
compiled: bool = false;
|
||||||
|
|
||||||
|
contextualTypeArguments: Map<string,Type> = new Map();
|
||||||
|
|
||||||
|
private breakMajor: i32 = 0;
|
||||||
|
private breakMinor: i32 = 0;
|
||||||
|
|
||||||
|
constructor(template: FunctionTemplate, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: ClassInstance | null) {
|
||||||
|
super(template.program, internalName);
|
||||||
|
this.template = template;
|
||||||
|
this.typeArguments = typeArguments;
|
||||||
|
this.parameters = parameters;
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.instanceMethodOf = instanceMethodOf;
|
||||||
|
let localIndex: i32 = 0;
|
||||||
|
if (instanceMethodOf) {
|
||||||
|
this.locals.set("this", new Local(template.program, "this", localIndex++, instanceMethodOf.type));
|
||||||
|
for (let [name, type] of instanceMethodOf.contextualTypeArguments)
|
||||||
|
this.contextualTypeArguments.set(name, type);
|
||||||
|
}
|
||||||
|
for (let i: i32 = 0, k: i32 = parameters.length; i < k; ++i) {
|
||||||
|
const parameter: Parameter = parameters[i];
|
||||||
|
this.locals.set(parameter.name, new Local(template.program, parameter.name, localIndex++, parameter.type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get isInstance(): bool { return this.instanceMethodOf != null; }
|
||||||
|
|
||||||
|
addLocal(type: Type, name: string | null = null): Local {
|
||||||
|
// if it has a name, check previously as this method will throw otherwise
|
||||||
|
let localIndex = this.parameters.length + this.additionalLocals.length;
|
||||||
|
if (this.instanceMethodOf) localIndex++; // plus 'this'
|
||||||
|
const local: Local = new Local(this.template.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
|
||||||
|
if (name) {
|
||||||
|
if (this.locals.has(<string>name))
|
||||||
|
throw new Error("unexpected duplicate local name");
|
||||||
|
this.locals.set(<string>name, local);
|
||||||
|
}
|
||||||
|
this.additionalLocals.push(type);
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
|
enterBreakContext(): string {
|
||||||
|
if (!this.breakMinor)
|
||||||
|
this.breakMajor++;
|
||||||
|
return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveBreakContext(): void {
|
||||||
|
if (--this.breakMinor < 0)
|
||||||
|
throw new Error("unexpected unbalanced break context");
|
||||||
|
if (this.breakMinor == 0 && !--this.breakMajor)
|
||||||
|
this.breakContext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClassTemplate extends Namespace {
|
||||||
|
|
||||||
|
kind = ElementKind.CLASS;
|
||||||
|
declaration: ClassDeclaration | null;
|
||||||
|
fieldDeclarations: Map<string,FieldDeclaration>;
|
||||||
|
methodDeclarations: Map<string,MethodDeclaration>;
|
||||||
|
instances: Map<string,ClassInstance>;
|
||||||
|
isGeneric: bool;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||||
|
super(program, internalName, null);
|
||||||
|
this.declaration = declaration;
|
||||||
|
this.fieldDeclarations = new Map();
|
||||||
|
this.methodDeclarations = new Map();
|
||||||
|
this.instances = new Map();
|
||||||
|
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // builtins can set this
|
||||||
|
}
|
||||||
|
|
||||||
|
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||||
|
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't global exports */ false; }
|
||||||
|
|
||||||
|
instantiate(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): ClassInstance {
|
||||||
|
const key: string = typesToString(typeArguments, "", "");
|
||||||
|
let instance: ClassInstance | null = <ClassInstance | null>this.instances.get(key);
|
||||||
|
if (instance)
|
||||||
|
return instance;
|
||||||
|
if (!this.declaration)
|
||||||
|
throw new Error("unexpected instantiation of internal class");
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClassInstance extends Element {
|
||||||
|
|
||||||
|
kind = ElementKind.CLASSINSTANCE;
|
||||||
|
template: ClassTemplate;
|
||||||
|
typeArguments: Type[];
|
||||||
|
base: ClassInstance | null;
|
||||||
|
type: Type;
|
||||||
|
compiled: bool = false;
|
||||||
|
|
||||||
|
contextualTypeArguments: Map<string,Type> = new Map();
|
||||||
|
|
||||||
|
constructor(template: ClassTemplate, internalName: string, typeArguments: Type[], base: ClassInstance | null) {
|
||||||
|
super(template.program, internalName);
|
||||||
|
this.template = template;
|
||||||
|
this.typeArguments = typeArguments;
|
||||||
|
this.base = base;
|
||||||
|
this.type = (template.program.target == Target.WASM64 ? Type.usize64 : Type.usize32).asClass(this);
|
||||||
|
|
||||||
|
// inherit base class contextual type arguments
|
||||||
|
if (base)
|
||||||
|
for (let [name, type] of base.contextualTypeArguments)
|
||||||
|
this.contextualTypeArguments.set(name, type);
|
||||||
|
|
||||||
|
// apply instance-specific contextual type arguments
|
||||||
|
const declaration: ClassDeclaration | null = this.template.declaration;
|
||||||
|
if (declaration) { // irrelevant for builtins
|
||||||
|
const typeParameters: TypeParameter[] = declaration.typeParameters;
|
||||||
|
if (typeParameters.length != typeArguments.length)
|
||||||
|
throw new Error("unexpected type argument count mismatch");
|
||||||
|
for (let i: i32 = 0, k: i32 = typeArguments.length; i < k; ++i)
|
||||||
|
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InterfaceTemplate extends ClassTemplate {
|
||||||
|
|
||||||
|
kind = ElementKind.INTERFACE;
|
||||||
|
declaration: InterfaceDeclaration | null;
|
||||||
|
|
||||||
|
constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null) {
|
||||||
|
super(program, internalName, declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InterfaceInstance extends ClassInstance {
|
||||||
|
|
||||||
|
kind = ElementKind.INTERFACEINSTANCE;
|
||||||
|
base: InterfaceInstance | null;
|
||||||
|
|
||||||
|
constructor(template: InterfaceTemplate, internalName: string, typeArguments: Type[], base: InterfaceInstance | null) {
|
||||||
|
super(template, internalName, typeArguments, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -280,6 +280,7 @@ export function operatorTokenToString(token: Token): string {
|
|||||||
|
|
||||||
const possibleIdentifiers: Set<string> = new Set([
|
const possibleIdentifiers: Set<string> = new Set([
|
||||||
"from",
|
"from",
|
||||||
|
"global",
|
||||||
"module",
|
"module",
|
||||||
"namespace",
|
"namespace",
|
||||||
"type"
|
"type"
|
||||||
@ -302,6 +303,9 @@ export class Range {
|
|||||||
throw new Error("source mismatch");
|
throw new Error("source mismatch");
|
||||||
return new Range(a.source, a.start < b.start ? a.start : b.start, a.end > b.end ? a.end : b.end);
|
return new Range(a.source, a.start < b.start ? a.start : b.start, a.end > b.end ? a.end : b.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get atStart(): Range { return new Range(this.source, this.start, this.start); }
|
||||||
|
get atEnd(): Range { return new Range(this.source, this.end, this.end); }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tokenizer extends DiagnosticEmitter {
|
export class Tokenizer extends DiagnosticEmitter {
|
||||||
@ -1107,7 +1111,7 @@ function isOctalDigit(c: i32): bool {
|
|||||||
function isIdentifierStart(c: i32): bool {
|
function isIdentifierStart(c: i32): bool {
|
||||||
return c >= CharCode.A && c <= CharCode.Z
|
return c >= CharCode.A && c <= CharCode.Z
|
||||||
|| c >= CharCode.a && c <= CharCode.z
|
|| c >= CharCode.a && c <= CharCode.z
|
||||||
|| c == CharCode.$
|
// || c == CharCode.DOLLAR // reserved for internal in case we have to change the naming scheme
|
||||||
|| c == CharCode._
|
|| c == CharCode._
|
||||||
|| c > 0x7f && isUnicodeIdentifierStart(c);
|
|| c > 0x7f && isUnicodeIdentifierStart(c);
|
||||||
}
|
}
|
||||||
@ -1120,7 +1124,7 @@ function isIdentifierPart(c: i32): bool {
|
|||||||
return c >= CharCode.A && c <= CharCode.Z
|
return c >= CharCode.A && c <= CharCode.Z
|
||||||
|| c >= CharCode.a && c <= CharCode.z
|
|| c >= CharCode.a && c <= CharCode.z
|
||||||
|| c >= CharCode._0 && c <= CharCode._9
|
|| c >= CharCode._0 && c <= CharCode._9
|
||||||
|| c == CharCode.$
|
// || c == CharCode.DOLLAR // reserved for internal use, see above
|
||||||
|| c == CharCode._
|
|| c == CharCode._
|
||||||
|| c > 0x7f && isUnicodeIdentifierPart(c);
|
|| c > 0x7f && isUnicodeIdentifierPart(c);
|
||||||
}
|
}
|
||||||
|
@ -36,5 +36,14 @@
|
|||||||
"util/charcode.ts",
|
"util/charcode.ts",
|
||||||
"util/i64.ts",
|
"util/i64.ts",
|
||||||
"util/path.ts"
|
"util/path.ts"
|
||||||
|
],
|
||||||
|
"assembly": {
|
||||||
|
"exclude": [
|
||||||
|
"glue/js.t.ts",
|
||||||
|
"glue/js.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"glue/wasm.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
104
src/types.ts
104
src/types.ts
@ -1,3 +1,4 @@
|
|||||||
|
import { ClassInstance } from "./program";
|
||||||
import { sb } from "./util";
|
import { sb } from "./util";
|
||||||
|
|
||||||
export const enum TypeKind {
|
export const enum TypeKind {
|
||||||
@ -28,7 +29,7 @@ export class Type {
|
|||||||
|
|
||||||
kind: TypeKind;
|
kind: TypeKind;
|
||||||
size: i32;
|
size: i32;
|
||||||
classType: ClassType | null;
|
classType: ClassInstance | null;
|
||||||
nullable: bool = false;
|
nullable: bool = false;
|
||||||
nullableType: Type | null = null; // cached, of this type
|
nullableType: Type | null = null; // cached, of this type
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ export class Type {
|
|||||||
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
|
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
|
||||||
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
|
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
|
||||||
|
|
||||||
asClass(classType: ClassType): Type {
|
asClass(classType: ClassInstance): Type {
|
||||||
const ret: Type = new Type(this.kind, this.size);
|
const ret: Type = new Type(this.kind, this.size);
|
||||||
ret.classType = classType;
|
ret.classType = classType;
|
||||||
return ret;
|
return ret;
|
||||||
@ -73,7 +74,7 @@ export class Type {
|
|||||||
case TypeKind.U16: return "u16";
|
case TypeKind.U16: return "u16";
|
||||||
case TypeKind.U32: return "u32";
|
case TypeKind.U32: return "u32";
|
||||||
case TypeKind.U64: return "u64";
|
case TypeKind.U64: return "u64";
|
||||||
case TypeKind.USIZE: return this.classType && !kindOnly ? this.classType.toString() : "usize";
|
case TypeKind.USIZE: return this.classType != null && !kindOnly ? this.classType.toString() : "usize";
|
||||||
case TypeKind.BOOL: return "bool";
|
case TypeKind.BOOL: return "bool";
|
||||||
case TypeKind.F32: return "f32";
|
case TypeKind.F32: return "f32";
|
||||||
case TypeKind.F64: return "f64";
|
case TypeKind.F64: return "f64";
|
||||||
@ -101,101 +102,12 @@ export class Type {
|
|||||||
static readonly void: Type = new Type(TypeKind.VOID, 0);
|
static readonly void: Type = new Type(TypeKind.VOID, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FunctionType {
|
export function typesToString(types: Type[], prefix: string = "<", postfix: string = ">"): string {
|
||||||
|
const k: i32 = types.length;
|
||||||
typeArguments: Type[];
|
|
||||||
parameterTypes: Type[];
|
|
||||||
returnType: Type;
|
|
||||||
|
|
||||||
additionalLocals: Type[];
|
|
||||||
typeArgumentsMap: Map<string, Type> | null = null;
|
|
||||||
locals: Map<string, LocalType> = new Map();
|
|
||||||
breakContext: string | null = null;
|
|
||||||
|
|
||||||
private breakMajor: i32 = 0;
|
|
||||||
private breakMinor: i32 = 0;
|
|
||||||
|
|
||||||
constructor(typeArguments: Type[], parameterTypes: Type[], returnType: Type, parameterNames: string[] | null = null) {
|
|
||||||
this.typeArguments = typeArguments;
|
|
||||||
this.parameterTypes = parameterTypes;
|
|
||||||
this.returnType = returnType;
|
|
||||||
this.additionalLocals = new Array();
|
|
||||||
if (parameterNames) {
|
|
||||||
if (parameterTypes.length != (<string[]>parameterNames).length)
|
|
||||||
throw new Error("unexpected parameter count mismatch");;
|
|
||||||
for (let i: i32 = 0, k: i32 = parameterTypes.length; i < k; ++i) {
|
|
||||||
const name: string = (<string[]>parameterNames)[i];
|
|
||||||
if (this.locals.has(name))
|
|
||||||
throw new Error("duplicate parameter name");
|
|
||||||
this.locals.set(name, new LocalType(i, parameterTypes[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enterBreakContext(): string {
|
|
||||||
if (!this.breakMinor)
|
|
||||||
this.breakMajor++;
|
|
||||||
return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
leaveBreakContext(): void {
|
|
||||||
if (--this.breakMinor < 0)
|
|
||||||
throw new Error("unexpected unbalanced break context");
|
|
||||||
if (this.breakMinor == 0 && !--this.breakMajor)
|
|
||||||
this.breakContext = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
addLocal(type: Type, name: string | null = null): i32 {
|
|
||||||
// internal locals don't necessarily need names if referenced by index only
|
|
||||||
if (name && this.locals.has(<string>name))
|
|
||||||
throw new Error("duplicate local name");
|
|
||||||
const index: i32 = this.parameterTypes.length + this.additionalLocals.length;
|
|
||||||
this.additionalLocals.push(type);
|
|
||||||
if (name)
|
|
||||||
this.locals.set(<string>name, new LocalType(index, type));
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LocalType {
|
|
||||||
|
|
||||||
index: i32;
|
|
||||||
type: Type;
|
|
||||||
|
|
||||||
constructor(index: i32, type: Type) {
|
|
||||||
this.index = index;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ClassType {
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
typeArguments: Type[];
|
|
||||||
base: ClassType | null;
|
|
||||||
|
|
||||||
type: Type;
|
|
||||||
typeArgumentsMap: Map<string, Type> | null = null;
|
|
||||||
|
|
||||||
constructor(name: string, usizeType: Type, typeArguments: Type[], base: ClassType | null = null) {
|
|
||||||
this.name = name;
|
|
||||||
this.typeArguments = typeArguments;
|
|
||||||
this.base = base;
|
|
||||||
this.type = usizeType.asClass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
let str: string = this.typeArguments.length ? this.name + typeArgumentsToString(this.typeArguments) : this.name;
|
|
||||||
return this.type.nullable ? str + " | null" : str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function typeArgumentsToString(typeArguments: Type[]): string {
|
|
||||||
const k: i32 = typeArguments.length;
|
|
||||||
if (!k)
|
if (!k)
|
||||||
return "";
|
return "";
|
||||||
sb.length = 0;
|
sb.length = 0;
|
||||||
for (let i: i32 = 0; i < k; ++i)
|
for (let i: i32 = 0; i < k; ++i)
|
||||||
sb[i] = typeArguments[i].toString();
|
sb[i] = types[i].toString();
|
||||||
return "<" + sb.join(",") + ">";
|
return prefix + sb.join(",") + postfix;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ export const enum CharCode {
|
|||||||
OGHAM = 0x1680,
|
OGHAM = 0x1680,
|
||||||
|
|
||||||
_ = 0x5F,
|
_ = 0x5F,
|
||||||
$ = 0x24,
|
|
||||||
|
|
||||||
_0 = 0x30,
|
_0 = 0x30,
|
||||||
_1 = 0x31,
|
_1 = 0x31,
|
||||||
@ -106,6 +105,7 @@ export const enum CharCode {
|
|||||||
CLOSEPAREN = 0x29,
|
CLOSEPAREN = 0x29,
|
||||||
COLON = 0x3A,
|
COLON = 0x3A,
|
||||||
COMMA = 0x2C,
|
COMMA = 0x2C,
|
||||||
|
DOLLAR = 0x24,
|
||||||
DOT = 0x2E,
|
DOT = 0x2E,
|
||||||
DOUBLEQUOTE = 0x22,
|
DOUBLEQUOTE = 0x22,
|
||||||
EQUALS = 0x3D,
|
EQUALS = 0x3D,
|
||||||
|
@ -511,6 +511,10 @@ export class U64 extends I64 {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get fitsInU32(): bool {
|
||||||
|
return this.hi == 0;
|
||||||
|
}
|
||||||
|
|
||||||
comp32(lo: i32, hi: i32): i32 {
|
comp32(lo: i32, hi: i32): i32 {
|
||||||
// uses both a cast and a js-like shift for portability
|
// uses both a cast and a js-like shift for portability
|
||||||
return ((hi as u32 >>> 0) > (this.hi as u32 >>> 0)) || (hi == this.hi && (lo as u32 >>> 0) > (this.lo as u32 >>> 0)) ? -1 : 1;
|
return ((hi as u32 >>> 0) > (this.hi as u32 >>> 0)) || (hi == this.hi && (lo as u32 >>> 0) > (this.lo as u32 >>> 0)) ? -1 : 1;
|
||||||
|
17
std/array.d.ts
vendored
Normal file
17
std/array.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class Array<T> {
|
||||||
|
length: i32;
|
||||||
|
readonly capacity: i32;
|
||||||
|
readonly data: usize;
|
||||||
|
constructor(capacity: i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare class Int8Array extends Array<i8> {}
|
||||||
|
declare class Int16Array extends Array<i16> {}
|
||||||
|
declare class Int32Array extends Array<i32> {}
|
||||||
|
declare class Uint8Array extends Array<u8> {}
|
||||||
|
declare class Uint16Array extends Array<u16> {}
|
||||||
|
declare class Uint32Array extends Array<u32> {}
|
||||||
|
declare class Float32Array extends Array<f32> {}
|
||||||
|
declare class Float64Array extends Array<f64> {}
|
17
std/array.ts
Normal file
17
std/array.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Array<T> {
|
||||||
|
|
||||||
|
length: i32;
|
||||||
|
readonly capacity: i32;
|
||||||
|
readonly data: usize;
|
||||||
|
|
||||||
|
constructor(capacity: i32) {
|
||||||
|
if (capacity < 0)
|
||||||
|
throw new RangeError("capacity out of bounds");
|
||||||
|
this.length = capacity;
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.data = Memory.allocate(sizeof<T>() * capacity);
|
||||||
|
}
|
||||||
|
}
|
10
std/error.d.ts
vendored
Normal file
10
std/error.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class Error {
|
||||||
|
message: string;
|
||||||
|
constructor(message: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare class RangeError extends Error {}
|
||||||
|
declare class ReferenceError extends Error {}
|
||||||
|
declare class TypeError extends Error {}
|
20
std/error.ts
Normal file
20
std/error.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Error {
|
||||||
|
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
constructor(message: string) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class RangeError extends Error {}
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class ReferenceError extends Error {}
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class TypeError extends Error {}
|
1
std/map.d.ts
vendored
Normal file
1
std/map.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
22
std/map.ts
Normal file
22
std/map.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Map<K,V> {
|
||||||
|
private keys: K[];
|
||||||
|
private values: V[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.keys = [];
|
||||||
|
this.values = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
has(key: K): bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key: K, value: V): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
}
|
||||||
|
}
|
4
std/math.d.ts
vendored
Normal file
4
std/math.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class Math {
|
||||||
|
}
|
5
std/math.ts
Normal file
5
std/math.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Math {
|
||||||
|
}
|
8
std/memory.d.ts
vendored
Normal file
8
std/memory.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class Memory {
|
||||||
|
static allocate(size: usize): usize;
|
||||||
|
static free(ptr: usize): void;
|
||||||
|
static copy(src: usize, dst: usize, count: usize): void;
|
||||||
|
static compare(src: usize, dst: usize, count: usize): i32;
|
||||||
|
}
|
27
std/memory.ts
Normal file
27
std/memory.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Memory {
|
||||||
|
|
||||||
|
static allocate(size: usize): usize {
|
||||||
|
const ptr: usize = load<usize>(sizeof<usize>());
|
||||||
|
store<usize>(sizeof<usize>(), ptr + size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static free(ptr: usize): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
static copy(src: usize, dst: usize, count: usize): void {
|
||||||
|
for (let i: usize = 0; i < count; ++i)
|
||||||
|
store<u8>(dst + i, load<u8>(src + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static compare(src: usize, dst: usize, count: usize): i32 {
|
||||||
|
for (let i: usize = 0; i < count; ++i) {
|
||||||
|
const d: i32 = (load<u8>(src + i) as i32) - (load<u8>(dst + i) as i32);
|
||||||
|
if (d) return d;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
4
std/set.d.ts
vendored
Normal file
4
std/set.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class Set<T> {
|
||||||
|
}
|
5
std/set.ts
Normal file
5
std/set.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
class Set<T> {
|
||||||
|
}
|
11
std/string.d.ts
vendored
Normal file
11
std/string.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
declare class String {
|
||||||
|
readonly length: i32;
|
||||||
|
constructor(length: i32);
|
||||||
|
static fromCharCode(c1: i32, c2?: i32);
|
||||||
|
static equals(a: string, b: string): bool;
|
||||||
|
static concat(a: string, b: string): string;
|
||||||
|
charCodeAt(index: i32): u16;
|
||||||
|
concat(other: string): string;
|
||||||
|
}
|
58
std/string.ts
Normal file
58
std/string.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/// <reference path="../assembly.d.ts" />
|
||||||
|
|
||||||
|
@global()
|
||||||
|
@allocates()
|
||||||
|
@operator("==", String.equals)
|
||||||
|
@operator("!=", String.notEquals)
|
||||||
|
@operator("+", String.concat)
|
||||||
|
class String {
|
||||||
|
|
||||||
|
readonly length: i32;
|
||||||
|
|
||||||
|
constructor(length: i32) {
|
||||||
|
if (length < 0)
|
||||||
|
throw new RangeError("invalid length");
|
||||||
|
const data: usize = Memory.allocate(4 + length);
|
||||||
|
store<i32>(data, length);
|
||||||
|
return classof<String>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromCharCode(c1: i32 /* sic */, c2: i32 = -1): String {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
static equals(a: String, b: String): bool {
|
||||||
|
const aLength: i32 = a.length;
|
||||||
|
return aLength == b.length && !Memory.compare(pointerof(a) + 4, pointerof(b) + 4, aLength << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static notEquals(a: String, b: String): bool {
|
||||||
|
const aLength: i32 = a.length;
|
||||||
|
return aLength != b.length || Memory.compare(pointerof(a) + 4, pointerof(b) + 4, aLength << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static concat(a: String, b: String): String {
|
||||||
|
const aLength: i32 = a.length;
|
||||||
|
const bLength: i32 = b.length;
|
||||||
|
const combinedLength: i32 = aLength + bLength;
|
||||||
|
if (combinedLength < 0)
|
||||||
|
throw new RangeError("invalid length");
|
||||||
|
const aByteLength: i32 = aLength << 1;
|
||||||
|
const bByteLength: i32 = bLength << 1;
|
||||||
|
const data: usize = Memory.allocate(4 + combinedLength);
|
||||||
|
store<i32>(data, combinedLength);
|
||||||
|
Memory.copy(pointerof(a) + 4, data + 4, aByteLength);
|
||||||
|
Memory.copy(pointerof(b) + 4, data + 4 + aByteLength, bByteLength);
|
||||||
|
return classof<String>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
charCodeAt(index: i32): u16 {
|
||||||
|
if (index < 0 || index > this.length)
|
||||||
|
throw new RangeError("index out of bounds");
|
||||||
|
return load<u32>(pointerof(this) + 4 + index << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
concat(other: String): String {
|
||||||
|
return String.concat(this, other);
|
||||||
|
}
|
||||||
|
}
|
15
std/tsconfig.json
Normal file
15
std/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"noLib": true,
|
||||||
|
"experimentalDecorators": true
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"array.ts",
|
||||||
|
"error.ts",
|
||||||
|
"map.ts",
|
||||||
|
"math.ts",
|
||||||
|
"memory.ts",
|
||||||
|
"set.ts",
|
||||||
|
"string.ts"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user