Reintroduce builtin decorator so these can appear anywhere in stdlib again

Avoids wrapping an undocumented function within 'memory.size' for example.
This commit is contained in:
dcodeIO
2018-07-19 02:10:04 +02:00
parent 96411c7398
commit 26e46f6f86
80 changed files with 6889 additions and 7157 deletions

View File

@ -1122,7 +1122,8 @@ export enum DecoratorKind {
UNMANAGED,
SEALED,
INLINE,
EXTERNAL
EXTERNAL,
BUILTIN
}
/** Returns the kind of the specified decorator. Defaults to {@link DecoratorKind.CUSTOM}. */
@ -1132,6 +1133,10 @@ export function decoratorNameToKind(name: Expression): DecoratorKind {
let nameStr = (<IdentifierExpression>name).text;
assert(nameStr.length);
switch (nameStr.charCodeAt(0)) {
case CharCode.b: {
if (nameStr == "builtin") return DecoratorKind.BUILTIN;
break;
}
case CharCode.e: {
if (nameStr == "external") return DecoratorKind.EXTERNAL;
break;

View File

@ -1871,7 +1871,7 @@ export function compileCall(
// host operations
case "__memory_size": { // __memory_size() -> i32
case "memory.size": { // memory.size() -> i32
compiler.currentType = Type.i32;
if (operands.length != 0) {
compiler.error(
@ -1887,7 +1887,7 @@ export function compileCall(
}
return module.createHost(HostOp.CurrentMemory);
}
case "__memory_grow": { // __memory_grow(pages: i32) -> i32
case "memory.grow": { // memory.grow(pages: i32) -> i32
compiler.currentType = Type.i32;
if (operands.length != 1) {
compiler.error(
@ -1907,7 +1907,7 @@ export function compileCall(
return module.createHost(HostOp.GrowMemory, null, [ arg0 ]);
}
// see: https://github.com/WebAssembly/bulk-memory-operations
case "__memory_copy": { // __memory_copy(dest: usize, src: usize: n: usize) -> void
case "memory.copy": { // memory.copy(dest: usize, src: usize: n: usize) -> void
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
@ -1944,7 +1944,7 @@ export function compileCall(
throw new Error("not implemented");
// return module.createHost(HostOp.MoveMemory, null, [ arg0, arg1, arg2 ]);
}
case "__memory_fill": { // __memory_fill(dest: usize, value: u8, n: usize) -> void
case "memory.fill": { // memory.fill(dest: usize, value: u8, n: usize) -> void
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
@ -2629,7 +2629,7 @@ export function compileCall(
// gc
case "__gc_iterate_roots": {
case "gc.iterateRoots": {
// TOOD: make it so that this can only be called from a library file?
if (typeArguments) {
compiler.error(

View File

@ -58,24 +58,22 @@ export enum CommonFlags {
// Compilation states
/** Is a builtin. */
BUILTIN = 1 << 21,
/** Is compiled. */
COMPILED = 1 << 22,
COMPILED = 1 << 21,
/** Has a constant value and is therefore inlined. */
INLINED = 1 << 23,
INLINED = 1 << 22,
/** Is scoped. */
SCOPED = 1 << 24,
SCOPED = 1 << 23,
/** Is a trampoline. */
TRAMPOLINE = 1 << 25,
TRAMPOLINE = 1 << 24,
/** Is a virtual method. */
VIRTUAL = 1 << 26,
VIRTUAL = 1 << 25,
/** Is the main function. */
MAIN = 1 << 27,
MAIN = 1 << 26,
// Other
QUOTED = 1 << 28
QUOTED = 1 << 27
}
/** Path delimiter inserted between file system levels. */

View File

@ -727,7 +727,7 @@ export class Compiler extends DiagnosticEmitter {
}
// ambient builtins like 'HEAP_BASE' need to be resolved but are added explicitly
if (global.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN)) return true;
if (global.is(CommonFlags.AMBIENT) && global.hasDecorator(DecoratorFlags.BUILTIN)) return true;
var nativeType = global.type.toNativeType();
var isDeclaredConstant = global.is(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
@ -1007,7 +1007,7 @@ export class Compiler extends DiagnosticEmitter {
/** Compiles a readily resolved function instance. */
compileFunction(instance: Function): bool {
if (instance.is(CommonFlags.COMPILED)) return true;
assert(!instance.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN));
assert(!(instance.is(CommonFlags.AMBIENT) && instance.hasDecorator(DecoratorFlags.BUILTIN)));
instance.set(CommonFlags.COMPILED);
// check that modifiers are matching
@ -1229,6 +1229,7 @@ export class Compiler extends DiagnosticEmitter {
noTreeShaking || (<FunctionPrototype>element).is(CommonFlags.EXPORT)
) && !(<FunctionPrototype>element).is(CommonFlags.GENERIC)
) {
if (element.hasDecorator(DecoratorFlags.BUILTIN)) break;
this.compileFunctionUsingTypeArguments(
<FunctionPrototype>element,
[],
@ -2342,7 +2343,8 @@ export class Compiler extends DiagnosticEmitter {
: this.module.createI64(0);
}
case TypeKind.F64: {
if (!(element.is(CommonFlags.BUILTIN) && contextualType == Type.f32)) {
// monkey-patch for converting built-in floats to f32 implicitly
if (!(element.hasDecorator(DecoratorFlags.BUILTIN) && contextualType == Type.f32)) {
return this.module.createF64((<VariableLikeElement>element).constantFloatValue);
}
// otherwise fall-through: basically precomputes f32.demote/f64 of NaN / Infinity
@ -4967,7 +4969,7 @@ export class Compiler extends DiagnosticEmitter {
let typeArguments = expression.typeArguments;
// builtins handle present respectively omitted type arguments on their own
if (prototype.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN)) {
if (prototype.hasDecorator(DecoratorFlags.BUILTIN)) {
return this.compileCallExpressionBuiltin(prototype, expression, contextualType);
}

View File

@ -86,8 +86,6 @@ import {
nodeIsGenericCallable
} from "./ast";
const builtinsFile = LIBRARY_PREFIX + "builtins.ts";
/** Parser interface. */
export class Parser extends DiagnosticEmitter {
@ -135,11 +133,6 @@ export class Parser extends DiagnosticEmitter {
var program = this.program;
program.sources.push(source);
// mark the special builtins library file
if (source.normalizedPath == builtinsFile) {
source.set(CommonFlags.BUILTIN);
}
// tokenize and parse
var tn = new Tokenizer(source, program.diagnostics);
tn.onComment = this.onComment;
@ -176,9 +169,6 @@ export class Parser extends DiagnosticEmitter {
decorators.push(decorator);
}
// mark builtins
flags |= (tn.source.flags & CommonFlags.BUILTIN);
// check modifiers
var exportStart: i32 = 0;
var exportEnd: i32 = 0;

View File

@ -708,7 +708,16 @@ export class Program extends DiagnosticEmitter {
let kind = decoratorNameToKind(decorator.name);
let flag = decoratorKindToFlag(kind);
if (flag) {
if (!(acceptedFlags & flag)) {
if (flag == DecoratorFlags.BUILTIN) {
if (decorator.range.source.isLibrary) {
presentFlags |= flag;
} else {
this.error(
DiagnosticCode.Decorator_0_is_not_valid_here,
decorator.range, decorator.name.range.toString()
);
}
} else if (!(acceptedFlags & flag)) {
this.error(
DiagnosticCode.Decorator_0_is_not_valid_here,
decorator.range, decorator.name.range.toString()
@ -732,13 +741,9 @@ export class Program extends DiagnosticEmitter {
declaration: DeclarationStatement
): void {
var parentNode = declaration.parent;
// alias the element globally if it is ...
// alias globally if explicitly annotated @global or exported from a top-level library file
if (
// explicitly annotated with @global - or -
(element.hasDecorator(DecoratorFlags.GLOBAL)) ||
// part of the special builtins library file - or -
(declaration.range.source.is(CommonFlags.BUILTIN)) ||
// exported from a top-level library file
(
declaration.range.source.isLibrary &&
element.is(CommonFlags.EXPORT) &&
@ -758,10 +763,12 @@ export class Program extends DiagnosticEmitter {
);
} else {
this.elementsLookup.set(globalName, element);
// builtins can use the global name directly instead of being just an alias
if (element.is(CommonFlags.BUILTIN)) element.internalName = globalName;
}
}
// builtins use the global name directly
if (element.hasDecorator(DecoratorFlags.BUILTIN)) {
element.internalName = declaration.programLevelInternalName;
}
}
/** Initializes a class declaration. */
@ -2040,7 +2047,9 @@ export enum DecoratorFlags {
/** Is always inlined. */
INLINE = 1 << 6,
/** Is using a different external name. */
EXTERNAL = 1 << 7
EXTERNAL = 1 << 7,
/** Is a builtin. */
BUILTIN = 1 << 8
}
export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags {
@ -2054,6 +2063,7 @@ export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags {
case DecoratorKind.SEALED: return DecoratorFlags.SEALED;
case DecoratorKind.INLINE: return DecoratorFlags.INLINE;
case DecoratorKind.EXTERNAL: return DecoratorFlags.EXTERNAL;
case DecoratorKind.BUILTIN: return DecoratorFlags.BUILTIN;
default: return DecoratorFlags.NONE;
}
}
@ -2375,7 +2385,7 @@ export class Function extends Element {
this.flags = prototype.flags;
this.decoratorFlags = prototype.decoratorFlags;
this.contextualTypeArguments = contextualTypeArguments;
if (!(prototype.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN) || prototype.is(CommonFlags.DECLARE))) {
if (!(prototype.is(CommonFlags.AMBIENT))) {
let localIndex = 0;
if (parent && parent.kind == ElementKind.CLASS) {
assert(this.is(CommonFlags.INSTANCE));