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:
dcodeIO
2018-06-28 01:44:32 +02:00
parent 27e61f8f67
commit 9c16363796
110 changed files with 17069 additions and 16757 deletions

View File

@ -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. */

View File

@ -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;

View File

@ -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;
}
}