mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-22 11:11:43 +00:00
Fix game-of-life example inconsistencies; Fix ternary expression issues in void contexts and variable statements; Simplify HEAP_BASE handling
This commit is contained in:
@ -47,25 +47,6 @@ import {
|
||||
OperatorKind
|
||||
} from "./program";
|
||||
|
||||
/** Compiles a get of a built-in global. */
|
||||
export function compileGetConstant(
|
||||
compiler: Compiler,
|
||||
global: Global,
|
||||
reportNode: Node
|
||||
): ExpressionRef {
|
||||
switch (global.internalName) {
|
||||
case "HEAP_BASE": { // never inlined for linking purposes
|
||||
compiler.currentType = compiler.options.usizeType;
|
||||
return compiler.module.createGetGlobal("HEAP_BASE", compiler.currentType.toNativeType());
|
||||
}
|
||||
}
|
||||
compiler.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
reportNode.range
|
||||
);
|
||||
return compiler.module.createUnreachable();
|
||||
}
|
||||
|
||||
/** Compiles a call to a built-in function. */
|
||||
export function compileCall(
|
||||
compiler: Compiler,
|
||||
|
106
src/compiler.ts
106
src/compiler.ts
@ -5,7 +5,6 @@
|
||||
|
||||
import {
|
||||
compileCall as compileBuiltinCall,
|
||||
compileGetConstant as compileBuiltinGetConstant,
|
||||
compileAllocate as compileBuiltinAllocate,
|
||||
compileAbort as compileBuiltinAbort
|
||||
} from "./builtins";
|
||||
@ -458,8 +457,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
compileGlobal(global: Global): bool {
|
||||
if (global.is(CommonFlags.COMPILED) || global.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN)) return true;
|
||||
global.set(CommonFlags.COMPILED); // ^ built-ins are compiled on use
|
||||
if (global.is(CommonFlags.COMPILED)) return true;
|
||||
global.set(CommonFlags.COMPILED);
|
||||
|
||||
var module = this.module;
|
||||
var declaration = global.declaration;
|
||||
@ -510,6 +509,9 @@ 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;
|
||||
|
||||
var nativeType = global.type.toNativeType();
|
||||
var isConstant = global.isAny(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
|
||||
|
||||
@ -928,18 +930,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (signature.requiredParameters < signature.parameterTypes.length) {
|
||||
// export the trampoline if the function takes optional parameters
|
||||
instance = this.ensureTrampoline(instance);
|
||||
if (!this.argcSet) {
|
||||
this.ensureArgumentCount(0);
|
||||
this.argcSet = module.addFunction("~setargc",
|
||||
this.ensureFunctionType([ Type.u32 ], Type.void),
|
||||
null,
|
||||
module.createSetGlobal("~argc",
|
||||
module.createGetLocal(0, NativeType.I32)
|
||||
)
|
||||
);
|
||||
// export a helper to set argc prior to calling it
|
||||
module.addFunctionExport("~setargc", "_setargc");
|
||||
}
|
||||
this.ensureArgcSet();
|
||||
}
|
||||
module.addFunctionExport(instance.internalName, mangleExportName(instance));
|
||||
}
|
||||
@ -5098,6 +5089,38 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
/** Makes sure that the argument count helper global is present and returns its name. */
|
||||
private ensureArgcVar(): string {
|
||||
var internalName = "~argc";
|
||||
if (!this.argcVar) {
|
||||
let module = this.module;
|
||||
this.argcVar = module.addGlobal(
|
||||
internalName,
|
||||
NativeType.I32,
|
||||
true,
|
||||
module.createI32(0)
|
||||
);
|
||||
}
|
||||
return internalName;
|
||||
}
|
||||
|
||||
/** Makes sure that the argument count helper setter is present and returns its name. */
|
||||
private ensureArgcSet(): string {
|
||||
var internalName = "~setargc";
|
||||
if (!this.argcSet) {
|
||||
let module = this.module;
|
||||
this.argcSet = module.addFunction(internalName,
|
||||
this.ensureFunctionType([ Type.u32 ], Type.void),
|
||||
null,
|
||||
module.createSetGlobal(this.ensureArgcVar(),
|
||||
module.createGetLocal(0, NativeType.I32)
|
||||
)
|
||||
);
|
||||
module.addFunctionExport(internalName, "_setargc");
|
||||
}
|
||||
return internalName;
|
||||
}
|
||||
|
||||
/** Creates a direct call to the specified function. */
|
||||
makeCallDirect(
|
||||
instance: Function,
|
||||
@ -5137,7 +5160,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let nativeReturnType = returnType.toNativeType();
|
||||
this.currentType = returnType;
|
||||
return module.createBlock(null, [
|
||||
this.ensureArgumentCount(numArguments),
|
||||
module.createSetGlobal(this.ensureArgcVar(), module.createI32(numArguments)),
|
||||
module.createCall(instance.internalName, operands, nativeReturnType)
|
||||
], nativeReturnType);
|
||||
}
|
||||
@ -5224,25 +5247,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var returnType = signature.returnType;
|
||||
this.currentType = returnType;
|
||||
return module.createBlock(null, [
|
||||
this.ensureArgumentCount(numArguments), // might still be calling a trampoline
|
||||
module.createSetGlobal(this.ensureArgcVar(), // might still be calling a trampoline
|
||||
module.createI32(numArguments)
|
||||
),
|
||||
module.createCallIndirect(indexArg, operands, signature.toSignatureString())
|
||||
], returnType.toNativeType());
|
||||
}
|
||||
|
||||
/** Makes sure that the argument count helper global is present and returns an expression that sets it. */
|
||||
private ensureArgumentCount(argumentCount: i32): ExpressionRef {
|
||||
var module = this.module;
|
||||
if (!this.argcVar) {
|
||||
this.argcVar = module.addGlobal(
|
||||
"~argc",
|
||||
NativeType.I32,
|
||||
true,
|
||||
module.createI32(0)
|
||||
);
|
||||
}
|
||||
return module.createSetGlobal("~argc", module.createI32(argumentCount));
|
||||
}
|
||||
|
||||
compileCommaExpression(expression: CommaExpression, contextualType: Type): ExpressionRef {
|
||||
var expressions = expression.expressions;
|
||||
var numExpressions = expressions.length;
|
||||
@ -5430,9 +5441,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return this.module.createGetLocal(localIndex, localType.toNativeType());
|
||||
}
|
||||
case ElementKind.GLOBAL: {
|
||||
if (target.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN)) {
|
||||
return compileBuiltinGetConstant(this, <Global>target, expression);
|
||||
}
|
||||
if (!this.compileGlobal(<Global>target)) { // reports; not yet compiled if a static field
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
@ -5898,9 +5906,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
switch (target.kind) {
|
||||
case ElementKind.GLOBAL: { // static property
|
||||
if (target.is(CommonFlags.AMBIENT | CommonFlags.BUILTIN)) {
|
||||
return compileBuiltinGetConstant(this, <Global>target, propertyAccess);
|
||||
}
|
||||
if (!this.compileGlobal(<Global>target)) { // reports; not yet compiled if a static field
|
||||
return module.createUnreachable();
|
||||
}
|
||||
@ -6008,6 +6013,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var currentFunction = this.currentFunction;
|
||||
var ifThenExpr: ExpressionRef;
|
||||
var ifElseExpr: ExpressionRef;
|
||||
var ifThenType: Type;
|
||||
var ifElseType: Type;
|
||||
|
||||
// if part of a constructor, keep track of memory allocations
|
||||
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
|
||||
@ -6015,14 +6022,16 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
flow = flow.enterBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
ifThenExpr = this.compileExpression(ifThen, contextualType);
|
||||
ifThenExpr = this.compileExpressionRetainType(ifThen, contextualType);
|
||||
ifThenType = this.currentType;
|
||||
let ifThenAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||
flow = flow.leaveBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
|
||||
flow = flow.enterBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
ifElseExpr = this.compileExpression(ifElse, contextualType);
|
||||
ifElseExpr = this.compileExpressionRetainType(ifElse, contextualType);
|
||||
ifElseType = this.currentType;
|
||||
let ifElseAllocates = flow.is(FlowFlags.ALLOCATES);
|
||||
flow = flow.leaveBranchOrScope();
|
||||
currentFunction.flow = flow;
|
||||
@ -6031,10 +6040,23 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// otherwise simplify
|
||||
} else {
|
||||
ifThenExpr = this.compileExpression(ifThen, contextualType);
|
||||
ifElseExpr = this.compileExpression(ifElse, contextualType);
|
||||
ifThenExpr = this.compileExpressionRetainType(ifThen, contextualType);
|
||||
ifThenType = this.currentType;
|
||||
ifElseExpr = this.compileExpressionRetainType(ifElse, contextualType);
|
||||
ifElseType = this.currentType;
|
||||
}
|
||||
|
||||
var commonType = Type.commonCompatible(ifThenType, ifElseType, false);
|
||||
if (!commonType) {
|
||||
this.error(
|
||||
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
|
||||
expression.range, ifThenType.toString(), ifElseType.toString()
|
||||
);
|
||||
this.currentType = contextualType;
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
ifThenExpr = this.convertExpression(ifThenExpr, ifThenType, commonType, ConversionKind.IMPLICIT, ifThen);
|
||||
ifElseExpr = this.convertExpression(ifElseExpr, ifElseType, commonType, ConversionKind.IMPLICIT, ifElse);
|
||||
this.currentType = commonType;
|
||||
return this.module.createIf(condExpr, ifThenExpr, ifElseExpr);
|
||||
}
|
||||
|
||||
|
@ -3101,7 +3101,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
);
|
||||
return null;
|
||||
}
|
||||
let ifElse = this.parseExpression(tn);
|
||||
let ifElse = this.parseExpression(tn, precedence > Precedence.COMMA ? Precedence.COMMA + 1 : 0);
|
||||
if (!ifElse) return null;
|
||||
expr = Node.createTernaryExpression(
|
||||
expr,
|
||||
|
Reference in New Issue
Block a user