mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-20 18:26:40 +00:00
Fixes; Builtins; Testing in the interpreter
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import { PATH_DELIMITER } from "./constants";
|
||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||
import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module";
|
||||
import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef, getExpressionId, ExpressionId } from "./module";
|
||||
import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
|
||||
import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
||||
import { Token, Range } from "./tokenizer";
|
||||
@ -286,11 +286,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// globals
|
||||
|
||||
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): bool {
|
||||
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null {
|
||||
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
|
||||
if (!element || element.kind != ElementKind.GLOBAL)
|
||||
throw new Error("unexpected missing global");
|
||||
return this.compileGlobal(<Global>element);
|
||||
return this.compileGlobal(<Global>element)
|
||||
? <Global>element
|
||||
: null;
|
||||
}
|
||||
|
||||
compileGlobal(element: Global): bool {
|
||||
@ -333,7 +335,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else if (declaration) {
|
||||
if (declaration.initializer) {
|
||||
initializer = this.compileExpression(declaration.initializer, type);
|
||||
initializeInStart = declaration.initializer.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
|
||||
initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers
|
||||
} else {
|
||||
initializer = typeToNativeZero(this.module, type);
|
||||
initializeInStart = false;
|
||||
@ -342,12 +344,14 @@ export class Compiler extends DiagnosticEmitter {
|
||||
throw new Error("unexpected missing declaration or constant value");
|
||||
const internalName: string = element.internalName;
|
||||
if (initializeInStart) {
|
||||
this.module.addGlobal(internalName, nativeType, true, this.module.createI32(-1));
|
||||
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, type));
|
||||
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
|
||||
} else
|
||||
} else {
|
||||
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
|
||||
// if (element.globalExportName != null && element.hasConstantValue && !initializeInStart)
|
||||
// this.module.addGlobalExport(element.internalName, element.globalExportName);
|
||||
if (!element.isMutable) {
|
||||
// TODO: check export, requires updated binaryen.js with Module#addGlobalExport
|
||||
}
|
||||
}
|
||||
return element.isCompiled = true;
|
||||
}
|
||||
|
||||
@ -373,7 +377,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let initializeInStart: bool = false;
|
||||
if (declaration.value) {
|
||||
initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
|
||||
initializeInStart = declaration.value.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
|
||||
initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers
|
||||
} else if (previousInternalName == null) {
|
||||
initializer = this.module.createI32(0);
|
||||
initializeInStart = false;
|
||||
@ -385,10 +389,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
initializeInStart = true;
|
||||
}
|
||||
if (initializeInStart) {
|
||||
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(-1));
|
||||
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0));
|
||||
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
|
||||
} else
|
||||
} else {
|
||||
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
|
||||
// TODO: check export, requires updated binaryen.js with Module#addGlobalExport
|
||||
}
|
||||
} else
|
||||
throw new Error("unexpected missing declaration or constant value");
|
||||
previousInternalName = val.internalName;
|
||||
@ -1183,6 +1189,20 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.currentType = Type.bool;
|
||||
break;
|
||||
|
||||
case Token.EXCLAMATION_EQUALS:
|
||||
case Token.EXCLAMATION_EQUALS_EQUALS:
|
||||
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
|
||||
right = this.compileExpression(expression.right, this.currentType);
|
||||
op = this.currentType == Type.f32
|
||||
? BinaryOp.NeF32
|
||||
: this.currentType == Type.f64
|
||||
? BinaryOp.NeF64
|
||||
: this.currentType.isLongInteger
|
||||
? BinaryOp.NeI64
|
||||
: BinaryOp.NeI32;
|
||||
this.currentType = Type.bool;
|
||||
break;
|
||||
|
||||
case Token.EQUALS:
|
||||
return this.compileAssignment(expression.left, expression.right, contextualType);
|
||||
|
||||
@ -1544,7 +1564,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return this.module.createHost(HostOp.CurrentMemory);
|
||||
|
||||
case "grow_memory":
|
||||
this.warning(DiagnosticCode.Operation_is_unsafe, reportNode.range); // unsure
|
||||
// this.warning(DiagnosticCode.Operation_is_unsafe, reportNode.range); // unsure
|
||||
return this.module.createHost(HostOp.GrowMemory, null, operands);
|
||||
|
||||
case "unreachable":
|
||||
@ -1566,7 +1586,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
tempLocal = this.currentFunction.addLocal(Type.f32);
|
||||
return this.module.createBinary(BinaryOp.NeF32,
|
||||
this.module.createTeeLocal(tempLocal.index, operands[0]),
|
||||
this.module.createGetLocal(tempLocal.index, NativeType.F64)
|
||||
this.module.createGetLocal(tempLocal.index, NativeType.F32)
|
||||
);
|
||||
}
|
||||
break;
|
||||
@ -1604,6 +1624,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "assert":
|
||||
return this.module.createIf(
|
||||
this.module.createUnary(UnaryOp.EqzI32, operands[0]),
|
||||
this.module.createUnreachable()
|
||||
);
|
||||
}
|
||||
this.error(DiagnosticCode.Operation_not_supported, reportNode.range);
|
||||
return this.module.createUnreachable();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Range } from "./ast";
|
||||
import { isLineBreak, sb } from "./util";
|
||||
import { CharCode, isLineBreak, sb } from "./util";
|
||||
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||
|
||||
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||
@ -100,9 +100,9 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b
|
||||
sb.push("\n");
|
||||
let pos: i32 = range.start;
|
||||
let line: i32 = 1;
|
||||
let column: i32 = 0;
|
||||
let column: i32 = 1;
|
||||
while (pos-- > 0)
|
||||
if (isLineBreak(text.charCodeAt(pos)))
|
||||
if (text.charCodeAt(pos) == CharCode.LINEFEED)
|
||||
line++;
|
||||
else if (line == 1)
|
||||
column++;
|
||||
|
@ -613,6 +613,10 @@ export class Module {
|
||||
return _BinaryenModuleValidate(this.ref) == 1;
|
||||
}
|
||||
|
||||
interpret(): void {
|
||||
return _BinaryenModuleInterpret(this.ref);
|
||||
}
|
||||
|
||||
toBinary(): Uint8Array {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
@ -726,6 +730,10 @@ export class Relooper {
|
||||
}
|
||||
}
|
||||
|
||||
// export function setAPITracing(on: bool): void {
|
||||
// _BinaryenSetAPITracing(on ? 1 : 0);
|
||||
// }
|
||||
|
||||
// helpers
|
||||
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js
|
||||
|
||||
|
@ -1131,6 +1131,7 @@ function initializeBuiltins(program: Program): void {
|
||||
|
||||
const genericInt: Type[] = [ Type.i32, Type.i64 ];
|
||||
const genericFloat: Type[] = [ Type.f32, Type.f64 ];
|
||||
const usize: Type = program.target == Target.WASM64 ? Type.usize64 : Type.usize32;
|
||||
|
||||
addGenericUnaryBuiltin(program, "clz", genericInt);
|
||||
addGenericUnaryBuiltin(program, "ctz", genericInt);
|
||||
@ -1140,7 +1141,7 @@ function initializeBuiltins(program: Program): void {
|
||||
|
||||
addGenericUnaryBuiltin(program, "abs", genericFloat);
|
||||
addGenericUnaryBuiltin(program, "ceil", genericFloat);
|
||||
addGenericUnaryBuiltin(program, "copysign", genericFloat);
|
||||
addGenericBinaryBuiltin(program, "copysign", genericFloat);
|
||||
addGenericUnaryBuiltin(program, "floor", genericFloat);
|
||||
addGenericBinaryBuiltin(program, "max", genericFloat);
|
||||
addGenericBinaryBuiltin(program, "min", genericFloat);
|
||||
@ -1148,12 +1149,13 @@ function initializeBuiltins(program: Program): void {
|
||||
addGenericUnaryBuiltin(program, "sqrt", genericFloat);
|
||||
addGenericUnaryBuiltin(program, "trunc", genericFloat);
|
||||
|
||||
addBuiltin(program, "current_memory", [], Type.i32);
|
||||
addBuiltin(program, "grow_memory", [ Type.i32 ], Type.i32);
|
||||
addBuiltin(program, "current_memory", [], usize);
|
||||
addBuiltin(program, "grow_memory", [ usize ], usize);
|
||||
addBuiltin(program, "unreachable", [], Type.void);
|
||||
|
||||
addGenericUnaryTestBuiltin(program, "isNaN", genericFloat);
|
||||
addGenericUnaryTestBuiltin(program, "isFinite", genericFloat);
|
||||
addBuiltin(program, "assert", [ Type.bool ], Type.void);
|
||||
|
||||
// TODO: load, store, sizeof
|
||||
// sizeof, for example, has varying Ts but really shouldn't provide an instance for each class
|
||||
@ -1167,7 +1169,8 @@ function addBuiltin(program: Program, name: string, parameterTypes: Type[], retu
|
||||
const parameters: Parameter[] = new Array(k);
|
||||
for (let i: i32 = 0; i < k; ++i)
|
||||
parameters[i] = new Parameter("arg" + i, parameterTypes[i], null);
|
||||
prototype.instances.set("", new Function(prototype, name, [], parameters, Type.bool, null));
|
||||
prototype.instances.set("", new Function(prototype, name, [], parameters, returnType, null));
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
function addGenericUnaryBuiltin(program: Program, name: string, types: Type[]): void {
|
||||
|
Reference in New Issue
Block a user