mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-15 16:01:30 +00:00
Make the transition to ArrayBuffer backed Arrays (#70)
* Traverse base classes when resolving overloads * Implement preliminary TypedArray accessors * Extract decorator flags from common flags to make space * Add '**' overload * Implement basic explicit inlining * Support inlining of instance methods * Reduce number of required locals when inlining * Implement inlining of operator overloads * Fix issues when inlining generic functions
This commit is contained in:
46
src/ast.ts
46
src/ast.ts
@ -198,32 +198,9 @@ export abstract class Node {
|
||||
stmt.range = range;
|
||||
stmt.name = expression; expression.parent = stmt;
|
||||
stmt.arguments = args; if (args) setParent(args, stmt);
|
||||
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||
switch ((<IdentifierExpression>expression).text) {
|
||||
case "global": {
|
||||
stmt.decoratorKind = DecoratorKind.GLOBAL;
|
||||
break;
|
||||
}
|
||||
case "operator": {
|
||||
stmt.decoratorKind = DecoratorKind.OPERATOR;
|
||||
break;
|
||||
}
|
||||
case "unmanaged": {
|
||||
stmt.decoratorKind = DecoratorKind.UNMANAGED;
|
||||
break;
|
||||
}
|
||||
case "offset": {
|
||||
stmt.decoratorKind = DecoratorKind.OFFSET;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
stmt.decoratorKind = DecoratorKind.CUSTOM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stmt.decoratorKind = DecoratorKind.CUSTOM;
|
||||
}
|
||||
stmt.decoratorKind = expression.kind == NodeKind.IDENTIFIER
|
||||
? stringToDecoratorKind((<IdentifierExpression>expression).text)
|
||||
: DecoratorKind.CUSTOM;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@ -1075,7 +1052,22 @@ export enum DecoratorKind {
|
||||
GLOBAL,
|
||||
OPERATOR,
|
||||
UNMANAGED,
|
||||
OFFSET
|
||||
SEALED,
|
||||
INLINE,
|
||||
PRECOMPUTE
|
||||
}
|
||||
|
||||
/** Returns the decorator kind represented by the specified string. */
|
||||
export function stringToDecoratorKind(str: string): DecoratorKind {
|
||||
switch (str) {
|
||||
case "global": return DecoratorKind.GLOBAL;
|
||||
case "operator": return DecoratorKind.OPERATOR;
|
||||
case "unmanaged": return DecoratorKind.UNMANAGED;
|
||||
case "sealed": return DecoratorKind.SEALED;
|
||||
case "inline": return DecoratorKind.INLINE;
|
||||
case "precompute": return DecoratorKind.PRECOMPUTE;
|
||||
default: return DecoratorKind.CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a decorator. */
|
||||
|
@ -43,7 +43,8 @@ import {
|
||||
Global,
|
||||
FunctionPrototype,
|
||||
Class,
|
||||
Field
|
||||
Field,
|
||||
OperatorKind
|
||||
} from "./program";
|
||||
|
||||
/** Compiles a get of a built-in global. */
|
||||
@ -146,7 +147,7 @@ export function compileCall(
|
||||
compiler.currentType = Type.bool;
|
||||
if (!type) return module.createUnreachable();
|
||||
let classType = type.classReference;
|
||||
return classType != null && classType.prototype.fnIndexedGet != null
|
||||
return classType != null && classType.lookupOverload(OperatorKind.INDEXED_GET) != null
|
||||
? module.createI32(1)
|
||||
: module.createI32(0);
|
||||
}
|
||||
@ -1738,6 +1739,7 @@ export function compileCall(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let byteSize = (<Type[]>typeArguments)[0].byteSize;
|
||||
let alignLog2: i32;
|
||||
|
836
src/compiler.ts
836
src/compiler.ts
File diff suppressed because it is too large
Load Diff
@ -16,11 +16,13 @@ export enum DiagnosticCode {
|
||||
Basic_type_0_cannot_be_nullable = 204,
|
||||
Cannot_export_a_mutable_global = 205,
|
||||
Compiling_constant_with_non_constant_initializer_as_mutable = 206,
|
||||
Structs_cannot_extend_classes_and_vice_versa = 207,
|
||||
Structs_cannot_implement_interfaces = 208,
|
||||
Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa = 207,
|
||||
Unmanaged_classes_cannot_implement_interfaces = 208,
|
||||
Invalid_regular_expression_flags = 209,
|
||||
Implementation_0_must_match_the_signature_1 = 210,
|
||||
Class_0_is_sealed_and_cannot_be_extended = 211,
|
||||
Decorator_0_is_not_valid_here = 212,
|
||||
Duplicate_decorator = 213,
|
||||
Unterminated_string_literal = 1002,
|
||||
Identifier_expected = 1003,
|
||||
_0_expected = 1005,
|
||||
@ -122,11 +124,13 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 204: return "Basic type '{0}' cannot be nullable.";
|
||||
case 205: return "Cannot export a mutable global.";
|
||||
case 206: return "Compiling constant with non-constant initializer as mutable.";
|
||||
case 207: return "Structs cannot extend classes and vice-versa.";
|
||||
case 208: return "Structs cannot implement interfaces.";
|
||||
case 207: return "Unmanaged classes cannot extend managed classes and vice-versa.";
|
||||
case 208: return "Unmanaged classes cannot implement interfaces.";
|
||||
case 209: return "Invalid regular expression flags.";
|
||||
case 210: return "Implementation '{0}' must match the signature '{1}'.";
|
||||
case 211: return "Class '{0}' is sealed and cannot be extended.";
|
||||
case 212: return "Decorator '{0}' is not valid here.";
|
||||
case 213: return "Duplicate decorator.";
|
||||
case 1002: return "Unterminated string literal.";
|
||||
case 1003: return "Identifier expected.";
|
||||
case 1005: return "'{0}' expected.";
|
||||
|
@ -8,11 +8,13 @@
|
||||
"Basic type '{0}' cannot be nullable.": 204,
|
||||
"Cannot export a mutable global.": 205,
|
||||
"Compiling constant with non-constant initializer as mutable.": 206,
|
||||
"Structs cannot extend classes and vice-versa.": 207,
|
||||
"Structs cannot implement interfaces.": 208,
|
||||
"Unmanaged classes cannot extend managed classes and vice-versa.": 207,
|
||||
"Unmanaged classes cannot implement interfaces.": 208,
|
||||
"Invalid regular expression flags.": 209,
|
||||
"Implementation '{0}' must match the signature '{1}'.": 210,
|
||||
"Class '{0}' is sealed and cannot be extended.": 211,
|
||||
"Decorator '{0}' is not valid here.": 212,
|
||||
"Duplicate decorator.": 213,
|
||||
|
||||
"Unterminated string literal.": 1002,
|
||||
"Identifier expected.": 1003,
|
||||
|
@ -206,12 +206,8 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
|
||||
var len = text.length;
|
||||
var start = range.start;
|
||||
var end = range.end;
|
||||
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) {
|
||||
start--;
|
||||
}
|
||||
while (end < len && !isLineBreak(text.charCodeAt(end))) {
|
||||
end++;
|
||||
}
|
||||
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) start--;
|
||||
while (end < len && !isLineBreak(text.charCodeAt(end))) end++;
|
||||
var sb: string[] = [
|
||||
"\n ",
|
||||
text.substring(start, end),
|
||||
@ -225,9 +221,7 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
|
||||
if (range.start == range.end) {
|
||||
sb.push("^");
|
||||
} else {
|
||||
while (start++ < range.end) {
|
||||
sb.push("~");
|
||||
}
|
||||
while (start++ < range.end) sb.push("~");
|
||||
}
|
||||
if (useColors) sb.push(COLOR_RESET);
|
||||
return sb.join("");
|
||||
|
@ -75,7 +75,8 @@ import {
|
||||
ParameterNode,
|
||||
ParameterKind,
|
||||
ExportMember,
|
||||
SwitchCase
|
||||
SwitchCase,
|
||||
DeclarationStatement
|
||||
} from "../ast";
|
||||
|
||||
import {
|
||||
@ -912,7 +913,6 @@ export class ASTBuilder {
|
||||
}
|
||||
|
||||
visitFieldDeclaration(node: FieldDeclaration): void {
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -961,7 +961,6 @@ export class ASTBuilder {
|
||||
|
||||
visitFunctionDeclaration(node: FunctionDeclaration): void {
|
||||
var sb = this.sb;
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -1098,7 +1097,6 @@ export class ASTBuilder {
|
||||
}
|
||||
|
||||
visitInterfaceDeclaration(node: InterfaceDeclaration): void {
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -1138,7 +1136,6 @@ export class ASTBuilder {
|
||||
}
|
||||
|
||||
visitMethodDeclaration(node: MethodDeclaration): void {
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -1155,7 +1152,6 @@ export class ASTBuilder {
|
||||
}
|
||||
|
||||
visitNamespaceDeclaration(node: NamespaceDeclaration): void {
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -1315,7 +1311,6 @@ export class ASTBuilder {
|
||||
}
|
||||
|
||||
visitVariableStatement(node: VariableStatement): void {
|
||||
this.serializeBuiltinDecorators(node);
|
||||
var decorators = node.decorators;
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
@ -1398,19 +1393,6 @@ export class ASTBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
serializeBuiltinDecorators(node: Node): void {
|
||||
var sb = this.sb;
|
||||
var indentLevel = this.indentLevel;
|
||||
if (node.is(CommonFlags.GLOBAL)) {
|
||||
sb.push("@global\n");
|
||||
indent(sb, indentLevel);
|
||||
}
|
||||
if (node.is(CommonFlags.UNMANAGED)) {
|
||||
sb.push("@unmanaged\n");
|
||||
indent(sb, indentLevel);
|
||||
}
|
||||
}
|
||||
|
||||
serializeExternalModifiers(node: Node): void {
|
||||
var sb = this.sb;
|
||||
if (node.is(CommonFlags.EXPORT)) {
|
||||
|
@ -1099,6 +1099,45 @@ export class Relooper {
|
||||
}
|
||||
}
|
||||
|
||||
// export function hasSideEffects(expr: ExpressionRef): bool {
|
||||
// switch (_BinaryenExpressionGetId(expr)) {
|
||||
// case ExpressionId.GetLocal:
|
||||
// case ExpressionId.GetGlobal:
|
||||
// case ExpressionId.Const:
|
||||
// case ExpressionId.Nop:
|
||||
// case ExpressionId.Unreachable: {
|
||||
// return false;
|
||||
// }
|
||||
// case ExpressionId.Block: {
|
||||
// for (let i = 0, k = _BinaryenBlockGetNumChildren(expr); i < k; ++i) {
|
||||
// if (hasSideEffects(_BinaryenBlockGetChild(expr, i))) return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// case ExpressionId.If: {
|
||||
// return hasSideEffects(_BinaryenIfGetCondition(expr))
|
||||
// || hasSideEffects(_BinaryenIfGetIfTrue(expr))
|
||||
// || hasSideEffects(_BinaryenIfGetIfFalse(expr));
|
||||
// }
|
||||
// case ExpressionId.Unary: {
|
||||
// return hasSideEffects(_BinaryenUnaryGetValue(expr));
|
||||
// }
|
||||
// case ExpressionId.Binary: {
|
||||
// return hasSideEffects(_BinaryenBinaryGetLeft(expr))
|
||||
// || hasSideEffects(_BinaryenBinaryGetRight(expr));
|
||||
// }
|
||||
// case ExpressionId.Drop: {
|
||||
// return hasSideEffects(_BinaryenDropGetValue(expr));
|
||||
// }
|
||||
// case ExpressionId.Select: {
|
||||
// return hasSideEffects(_BinaryenSelectGetIfTrue(expr))
|
||||
// || hasSideEffects(_BinaryenSelectGetIfFalse(expr))
|
||||
// || hasSideEffects(_BinaryenSelectGetCondition(expr));
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// helpers
|
||||
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js
|
||||
|
||||
|
@ -27,7 +27,6 @@ import {
|
||||
} from "./util";
|
||||
|
||||
import {
|
||||
|
||||
Node,
|
||||
NodeKind,
|
||||
Source,
|
||||
@ -162,22 +161,9 @@ export class Parser extends DiagnosticEmitter {
|
||||
while (tn.skip(Token.AT)) {
|
||||
if (startPos < 0) startPos = tn.tokenPos;
|
||||
let decorator = this.parseDecorator(tn);
|
||||
if (!decorator) break;
|
||||
let name = decorator.name;
|
||||
if (name.kind == NodeKind.IDENTIFIER) {
|
||||
let text = (<IdentifierExpression>name).text;
|
||||
if (text == "global") {
|
||||
flags |= CommonFlags.GLOBAL;
|
||||
continue;
|
||||
}
|
||||
if (text == "unmananged") {
|
||||
flags |= CommonFlags.UNMANAGED;
|
||||
continue;
|
||||
}
|
||||
if (text == "sealed") {
|
||||
flags |= CommonFlags.SEALED;
|
||||
continue;
|
||||
}
|
||||
if (!decorator) {
|
||||
this.skipStatement(tn);
|
||||
continue;
|
||||
}
|
||||
if (!decorators) decorators = [];
|
||||
decorators.push(decorator);
|
||||
|
654
src/program.ts
654
src/program.ts
File diff suppressed because it is too large
Load Diff
@ -166,7 +166,7 @@ export enum Token {
|
||||
ENDOFFILE
|
||||
}
|
||||
|
||||
export function tokenFomKeyword(text: string): Token {
|
||||
export function tokenFromKeyword(text: string): Token {
|
||||
switch (text) {
|
||||
case "abstract": return Token.ABSTRACT;
|
||||
case "as": return Token.AS;
|
||||
@ -805,7 +805,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
let keywordText = text.substring(posBefore, this.pos);
|
||||
let keywordToken = tokenFomKeyword(keywordText);
|
||||
let keywordToken = tokenFromKeyword(keywordText);
|
||||
if (
|
||||
keywordToken != Token.INVALID &&
|
||||
!(preferIdentifier && tokenIsAlsoIdentifier(keywordToken))
|
||||
|
18
src/types.ts
18
src/types.ts
@ -80,7 +80,9 @@ export const enum TypeFlags {
|
||||
/** Is a reference type. */
|
||||
REFERENCE = 1 << 8,
|
||||
/** Is a nullable type. */
|
||||
NULLABLE = 1 << 9
|
||||
NULLABLE = 1 << 9,
|
||||
/** Is the special 'this' type. */
|
||||
THIS = 1 << 10
|
||||
}
|
||||
|
||||
/** Represents a resolved type. */
|
||||
@ -102,6 +104,8 @@ export class Type {
|
||||
nullableType: Type | null = null;
|
||||
/** Respective non-nullable type, if nullable. */
|
||||
nonNullableType: Type;
|
||||
/** Respective special 'this' type. */
|
||||
thisType: Type | null = null;
|
||||
|
||||
/** Constructs a new resolved type. */
|
||||
constructor(kind: TypeKind, flags: TypeFlags, size: i32) {
|
||||
@ -157,6 +161,18 @@ export class Type {
|
||||
return this.nullableType;
|
||||
}
|
||||
|
||||
/** Composes the respective 'this' type of this type. */
|
||||
asThis(): Type {
|
||||
var thisType = this.thisType;
|
||||
if (thisType) return thisType;
|
||||
thisType = new Type(this.kind, this.flags | TypeFlags.THIS, this.size);
|
||||
thisType.classReference = this.classReference;
|
||||
thisType.nullableType = this.nullableType;
|
||||
thisType.nonNullableType = this.nonNullableType;
|
||||
this.thisType = thisType;
|
||||
return thisType;
|
||||
}
|
||||
|
||||
/** Tests if a value of this type is assignable to a target of the specified type. */
|
||||
isAssignableTo(target: Type, signednessIsImportant: bool = false): bool {
|
||||
var currentClass: Class | null;
|
||||
|
Reference in New Issue
Block a user