mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-16 16:31:32 +00:00
Initial external decorator for annotating explicit import names; Use file name as default module name in imports; Emit empty memory if there are no static segments; Update TLSF and examples accordingly
This commit is contained in:
26
src/ast.ts
26
src/ast.ts
@ -1099,7 +1099,8 @@ export enum DecoratorKind {
|
||||
OPERATOR_POSTFIX,
|
||||
UNMANAGED,
|
||||
SEALED,
|
||||
INLINE
|
||||
INLINE,
|
||||
EXTERNAL
|
||||
}
|
||||
|
||||
/** Returns the kind of the specified decorator. Defaults to {@link DecoratorKind.CUSTOM}. */
|
||||
@ -1109,6 +1110,10 @@ export function decoratorNameToKind(name: Expression): DecoratorKind {
|
||||
let nameStr = (<IdentifierExpression>name).text;
|
||||
assert(nameStr.length);
|
||||
switch (nameStr.charCodeAt(0)) {
|
||||
case CharCode.e: {
|
||||
if (nameStr == "external") return DecoratorKind.EXTERNAL;
|
||||
break;
|
||||
}
|
||||
case CharCode.g: {
|
||||
if (nameStr == "global") return DecoratorKind.GLOBAL;
|
||||
break;
|
||||
@ -1471,6 +1476,8 @@ export class Source extends Node {
|
||||
normalizedPath: string;
|
||||
/** Path used internally. */
|
||||
internalPath: string;
|
||||
/** Simple path (last part without extension). */
|
||||
simplePath: string;
|
||||
/** Contained statements. */
|
||||
statements: Statement[];
|
||||
/** Full source text. */
|
||||
@ -1487,7 +1494,10 @@ export class Source extends Node {
|
||||
super();
|
||||
this.sourceKind = kind;
|
||||
this.normalizedPath = normalizedPath;
|
||||
this.internalPath = mangleInternalPath(this.normalizedPath);
|
||||
var internalPath = mangleInternalPath(this.normalizedPath);
|
||||
this.internalPath = internalPath;
|
||||
var pos = internalPath.lastIndexOf(PATH_DELIMITER);
|
||||
this.simplePath = pos >= 0 ? internalPath.substring(pos + 1) : internalPath;
|
||||
this.statements = new Array();
|
||||
this.range = new Range(this, 0, text.length);
|
||||
this.text = text;
|
||||
@ -1881,17 +1891,15 @@ export class WhileStatement extends Statement {
|
||||
statement: Statement;
|
||||
}
|
||||
|
||||
/** Tests if a specific decorator is present within the specified decorators. */
|
||||
export function hasDecorator(name: string, decorators: DecoratorNode[] | null): bool {
|
||||
/** Finds the first decorator matching the specified kind. */
|
||||
export function findDecorator(kind: DecoratorKind, decorators: DecoratorNode[] | null): DecoratorNode | null {
|
||||
if (decorators) {
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
let expression = decorators[i].name;
|
||||
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).text == name) {
|
||||
return true;
|
||||
}
|
||||
let decorator = decorators[i];
|
||||
if (decorator.decoratorKind == kind) return decorator;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Mangles a declaration's name to an internal name. */
|
||||
|
108
src/compiler.ts
108
src/compiler.ts
@ -84,12 +84,14 @@ import {
|
||||
TypeNode,
|
||||
Source,
|
||||
Range,
|
||||
DecoratorKind,
|
||||
|
||||
Statement,
|
||||
BlockStatement,
|
||||
BreakStatement,
|
||||
ClassDeclaration,
|
||||
ContinueStatement,
|
||||
DeclarationStatement,
|
||||
DoStatement,
|
||||
EmptyStatement,
|
||||
EnumDeclaration,
|
||||
@ -134,7 +136,8 @@ import {
|
||||
FieldDeclaration,
|
||||
|
||||
nodeIsConstantValue,
|
||||
isLastStatement
|
||||
isLastStatement,
|
||||
findDecorator
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -350,9 +353,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// determine initial page size
|
||||
var pages = i64_shr_u(i64_align(memoryOffset, 0x10000), i64_new(16, 0));
|
||||
var numPages = this.memorySegments.length
|
||||
? i64_low(i64_shr_u(i64_align(memoryOffset, 0x10000), i64_new(16, 0)))
|
||||
: 0;
|
||||
module.setMemory(
|
||||
i64_low(pages),
|
||||
numPages,
|
||||
this.options.isWasm64
|
||||
? Module.MAX_MEMORY_WASM64
|
||||
: Module.MAX_MEMORY_WASM32,
|
||||
@ -556,12 +561,16 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// constant global
|
||||
if (isConstant || this.options.hasFeature(Feature.MUTABLE_GLOBAL)) {
|
||||
global.set(CommonFlags.MODULE_IMPORT);
|
||||
if (declaration) {
|
||||
mangleImportName(global, declaration, global.parent);
|
||||
} else {
|
||||
mangleImportName_moduleName = "env";
|
||||
mangleImportName_elementName = global.simpleName;
|
||||
}
|
||||
module.addGlobalImport(
|
||||
global.internalName,
|
||||
global.parent
|
||||
? global.parent.simpleName
|
||||
: "env",
|
||||
global.simpleName,
|
||||
mangleImportName_moduleName,
|
||||
mangleImportName_elementName,
|
||||
nativeType
|
||||
);
|
||||
global.set(CommonFlags.COMPILED);
|
||||
@ -908,7 +917,21 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else {
|
||||
assert(body.kind == NodeKind.BLOCK);
|
||||
let stmts = this.compileStatements((<BlockStatement>body).statements);
|
||||
if (instance.is(CommonFlags.MAIN)) stmts.unshift(module.createCall("start", null, NativeType.None));
|
||||
if (instance.is(CommonFlags.MAIN)) {
|
||||
module.addGlobal("~started", NativeType.I32, true, module.createI32(0));
|
||||
stmts.unshift(
|
||||
module.createIf(
|
||||
module.createUnary(
|
||||
UnaryOp.EqzI32,
|
||||
module.createGetGlobal("~started", NativeType.I32)
|
||||
),
|
||||
module.createBlock(null, [
|
||||
module.createCall("start", null, NativeType.None),
|
||||
module.createSetGlobal("~started", module.createI32(1))
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
flow.finalize();
|
||||
if (isConstructor) {
|
||||
let nativeSizeType = this.options.nativeSizeType;
|
||||
@ -954,17 +977,24 @@ export class Compiler extends DiagnosticEmitter {
|
||||
stmt
|
||||
);
|
||||
|
||||
// concrete functions cannot have an annotated external name
|
||||
if (instance.hasDecorator(DecoratorFlags.EXTERNAL)) {
|
||||
let decorator = assert(findDecorator(DecoratorKind.EXTERNAL, declaration.decorators));
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
decorator.range
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
instance.set(CommonFlags.MODULE_IMPORT);
|
||||
mangleImportName(instance, declaration, instance.prototype.parent); // TODO: check for duplicates
|
||||
|
||||
// create the function import
|
||||
let parent = instance.prototype.parent;
|
||||
ref = module.addFunctionImport(
|
||||
instance.internalName,
|
||||
parent
|
||||
? parent.simpleName
|
||||
: "env",
|
||||
instance.simpleName,
|
||||
mangleImportName_moduleName,
|
||||
mangleImportName_elementName,
|
||||
typeRef
|
||||
);
|
||||
}
|
||||
@ -7402,3 +7432,55 @@ function mangleExportName(element: Element, simpleName: string = element.simpleN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mangleImportName(
|
||||
element: Element,
|
||||
declaration: DeclarationStatement,
|
||||
parentElement: Element | null = null
|
||||
): void {
|
||||
mangleImportName_moduleName = parentElement ? parentElement.simpleName : declaration.range.source.simplePath;
|
||||
mangleImportName_elementName = element.simpleName;
|
||||
|
||||
if (!element.hasDecorator(DecoratorFlags.EXTERNAL)) return;
|
||||
|
||||
var program = element.program;
|
||||
var decorator = assert(findDecorator(DecoratorKind.EXTERNAL, declaration.decorators));
|
||||
var args = decorator.arguments;
|
||||
if (args && args.length) {
|
||||
let arg = args[0];
|
||||
if (arg.kind == NodeKind.LITERAL && (<LiteralExpression>arg).literalKind == LiteralKind.STRING) {
|
||||
mangleImportName_elementName = (<StringLiteralExpression>arg).value;
|
||||
if (args.length >= 2) {
|
||||
arg = args[1];
|
||||
if (arg.kind == NodeKind.LITERAL && (<LiteralExpression>arg).literalKind == LiteralKind.STRING) {
|
||||
mangleImportName_moduleName = mangleImportName_elementName;
|
||||
mangleImportName_elementName = (<StringLiteralExpression>arg).value;
|
||||
if (args.length > 2) {
|
||||
program.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
decorator.range, "2", args.length.toString()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
program.error(
|
||||
DiagnosticCode.String_literal_expected,
|
||||
arg.range
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
program.error(
|
||||
DiagnosticCode.String_literal_expected,
|
||||
arg.range
|
||||
);
|
||||
}
|
||||
} else {
|
||||
program.error(
|
||||
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
||||
decorator.range, "1", "0"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var mangleImportName_moduleName: string;
|
||||
var mangleImportName_elementName: string;
|
||||
|
@ -1436,7 +1436,8 @@ export class Program extends DiagnosticEmitter {
|
||||
decorators
|
||||
? this.filterDecorators(decorators,
|
||||
DecoratorFlags.GLOBAL |
|
||||
DecoratorFlags.INLINE
|
||||
DecoratorFlags.INLINE |
|
||||
DecoratorFlags.EXTERNAL
|
||||
)
|
||||
: DecoratorFlags.NONE
|
||||
);
|
||||
@ -1718,14 +1719,17 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, namespace);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
);
|
||||
return;
|
||||
if (this.moduleLevelExports.get(simpleName) !== namespace) { // not merged
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.moduleLevelExports.set(simpleName, namespace);
|
||||
}
|
||||
namespace.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, namespace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1811,7 +1815,8 @@ export class Program extends DiagnosticEmitter {
|
||||
declaration,
|
||||
decorators
|
||||
? this.filterDecorators(decorators,
|
||||
DecoratorFlags.GLOBAL
|
||||
DecoratorFlags.GLOBAL |
|
||||
DecoratorFlags.EXTERNAL
|
||||
)
|
||||
: DecoratorFlags.NONE
|
||||
);
|
||||
@ -2491,7 +2496,9 @@ export enum DecoratorFlags {
|
||||
/** Is a sealed class. */
|
||||
SEALED = 1 << 5,
|
||||
/** Is always inlined. */
|
||||
INLINE = 1 << 6
|
||||
INLINE = 1 << 6,
|
||||
/** Is using a different external name. */
|
||||
EXTERNAL = 1 << 7
|
||||
}
|
||||
|
||||
export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags {
|
||||
@ -2504,6 +2511,7 @@ export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags {
|
||||
case DecoratorKind.UNMANAGED: return DecoratorFlags.UNMANAGED;
|
||||
case DecoratorKind.SEALED: return DecoratorFlags.SEALED;
|
||||
case DecoratorKind.INLINE: return DecoratorFlags.INLINE;
|
||||
case DecoratorKind.EXTERNAL: return DecoratorFlags.EXTERNAL;
|
||||
default: return DecoratorFlags.NONE;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user