mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 07:22:21 +00:00
Get rid of determineExpressionType
This commit is contained in:
parent
ca9c79185b
commit
d7c069b692
230
src/compiler.ts
230
src/compiler.ts
@ -179,11 +179,13 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
super(program.diagnostics);
|
super(program.diagnostics);
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.options = options ? options : new Options();
|
this.options = options ? options : new Options();
|
||||||
|
this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null`
|
||||||
this.module = this.options.noEmit ? Module.createStub() : Module.create();
|
this.module = this.options.noEmit ? Module.createStub() : Module.create();
|
||||||
|
|
||||||
|
// set up start function
|
||||||
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", "start", null);
|
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", "start", null);
|
||||||
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
|
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
|
||||||
this.currentFunction = this.startFunction = startFunctionInstance;
|
this.currentFunction = this.startFunction = startFunctionInstance;
|
||||||
this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
|
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
|
||||||
@ -208,7 +210,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (!typeRef)
|
if (!typeRef)
|
||||||
typeRef = this.module.addFunctionType("v", NativeType.None, []);
|
typeRef = this.module.addFunctionType("v", NativeType.None, []);
|
||||||
this.module.setStart(
|
this.module.setStart(
|
||||||
this.module.addFunction(this.startFunction.prototype.internalName, typeRef, typesToNativeTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody))
|
this.module.addFunction(this.startFunction.prototype.internalName, typeRef, typesToNativeTypes(this.startFunction.additionalLocals),
|
||||||
|
this.module.createBlock(null, this.startFunctionBody)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +230,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
initial.or32(0xffff);
|
initial.or32(0xffff);
|
||||||
initial.add32(1);
|
initial.add32(1);
|
||||||
}
|
}
|
||||||
initial.shru32(16); // initial size in 64k pages
|
initial.shru32(16); // now is initial size in 64k pages
|
||||||
this.module.setMemory(initial.toI32(), Module.MAX_MEMORY_WASM32 /* TODO: not WASM64 compatible yet */, this.memorySegments, this.options.target, "memory");
|
this.module.setMemory(initial.toI32(), Module.MAX_MEMORY_WASM32 /* TODO: not WASM64 compatible yet */, this.memorySegments, this.options.target, "memory");
|
||||||
|
|
||||||
return this.module;
|
return this.module;
|
||||||
@ -296,7 +300,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
default: {
|
default: {
|
||||||
const previousFunction: Function = this.currentFunction;
|
const previousFunction: Function = this.currentFunction;
|
||||||
this.currentFunction = this.startFunction;
|
this.currentFunction = this.startFunction;
|
||||||
this.startFunctionBody.push(this.compileStatement(statement));
|
const expr: ExpressionRef = this.compileStatement(statement);
|
||||||
|
if (!this.module.noEmit) this.startFunctionBody.push(expr);
|
||||||
this.currentFunction = previousFunction;
|
this.currentFunction = previousFunction;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -309,8 +314,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null {
|
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null {
|
||||||
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
|
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
|
||||||
if (!element || element.kind != ElementKind.GLOBAL)
|
if (!element || element.kind != ElementKind.GLOBAL)
|
||||||
throw new Error("unexpected missing global");
|
throw new Error("global expected");
|
||||||
if (!this.compileGlobal(<Global>element))
|
if (!this.compileGlobal(<Global>element)) // reports
|
||||||
return null;
|
return null;
|
||||||
if (isModuleExport(element, declaration)) {
|
if (isModuleExport(element, declaration)) {
|
||||||
if ((<Global>element).hasConstantValue)
|
if ((<Global>element).hasConstantValue)
|
||||||
@ -322,54 +327,58 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileGlobal(global: Global): bool {
|
compileGlobal(global: Global): bool {
|
||||||
if (global.isCompiled)
|
if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetGlobal(this, global)))
|
||||||
return true;
|
|
||||||
if (global.isBuiltIn && compileBuiltinGetGlobal(this, global))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const declaration: VariableLikeDeclarationStatement | null = global.declaration;
|
const declaration: VariableLikeDeclarationStatement | null = global.declaration;
|
||||||
if (!global.type) {
|
let type: Type | null = null;
|
||||||
if (declaration && declaration.type) {
|
let initExpr: ExpressionRef = 0;
|
||||||
global.type = this.program.resolveType(declaration.type); // reports
|
|
||||||
if (!global.type)
|
if (!global.type) { // infer type
|
||||||
|
if (declaration) {
|
||||||
|
if (declaration.type) {
|
||||||
|
global.type = this.program.resolveType(declaration.type); // reports
|
||||||
|
if (!global.type)
|
||||||
|
return false;
|
||||||
|
} else if (declaration.initializer) {
|
||||||
|
initExpr = this.compileExpression(declaration.initializer, Type.void, ConversionKind.NONE); // reports and returns unreachable
|
||||||
|
if (this.currentType == Type.void)
|
||||||
|
return false;
|
||||||
|
global.type = this.currentType;
|
||||||
|
} else {
|
||||||
|
this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd);
|
||||||
return false;
|
return false;
|
||||||
} else if (declaration && declaration.initializer) {
|
}
|
||||||
global.type = this.determineExpressionType(declaration.initializer);
|
|
||||||
if (!global.type)
|
|
||||||
return false;
|
|
||||||
} else if (declaration) {
|
|
||||||
this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd);
|
|
||||||
return false;
|
|
||||||
} else
|
} else
|
||||||
throw new Error("unable to infer type");
|
throw new Error("declaration expected");
|
||||||
}
|
}
|
||||||
if (this.module.noEmit)
|
|
||||||
return true;
|
|
||||||
const nativeType: NativeType = typeToNativeType(global.type);
|
const nativeType: NativeType = typeToNativeType(global.type);
|
||||||
let initializer: ExpressionRef;
|
|
||||||
let initializeInStart: bool = false;
|
let initializeInStart: bool = false;
|
||||||
|
|
||||||
if (global.hasConstantValue) {
|
if (global.hasConstantValue) {
|
||||||
if (global.type.isLongInteger)
|
if (global.type.isLongInteger)
|
||||||
initializer = global.constantIntegerValue ? this.module.createI64(global.constantIntegerValue.lo, global.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
initExpr = global.constantIntegerValue ? this.module.createI64(global.constantIntegerValue.lo, global.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
||||||
else if (global.type.kind == TypeKind.F32)
|
else if (global.type.kind == TypeKind.F32)
|
||||||
initializer = this.module.createF32(global.constantFloatValue);
|
initExpr = this.module.createF32(global.constantFloatValue);
|
||||||
else if (global.type.kind == TypeKind.F64)
|
else if (global.type.kind == TypeKind.F64)
|
||||||
initializer = this.module.createF64(global.constantFloatValue);
|
initExpr = this.module.createF64(global.constantFloatValue);
|
||||||
else if (global.type.isSmallInteger) {
|
else if (global.type.isSmallInteger) {
|
||||||
if (global.type.isSignedInteger) {
|
if (global.type.isSignedInteger) {
|
||||||
const shift: i32 = global.type.smallIntegerShift;
|
const shift: i32 = global.type.smallIntegerShift;
|
||||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0);
|
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0);
|
||||||
} else
|
} else
|
||||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & global.type.smallIntegerMask: 0);
|
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & global.type.smallIntegerMask: 0);
|
||||||
} else
|
} else
|
||||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() : 0);
|
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() : 0);
|
||||||
} else if (declaration) {
|
} else if (declaration) {
|
||||||
if (declaration.initializer) {
|
if (declaration.initializer) {
|
||||||
initializer = this.compileExpression(declaration.initializer, global.type);
|
if (!initExpr)
|
||||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
initExpr = this.compileExpression(declaration.initializer, global.type);
|
||||||
|
if (!this.module.noEmit && _BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
|
||||||
if (!global.isMutable) {
|
if (!global.isMutable) {
|
||||||
initializer = this.precomputeExpressionRef(initializer);
|
initExpr = this.precomputeExpressionRef(initExpr);
|
||||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
|
||||||
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
||||||
initializeInStart = true;
|
initializeInStart = true;
|
||||||
}
|
}
|
||||||
@ -377,33 +386,35 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
initializeInStart = true;
|
initializeInStart = true;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
initializer = typeToNativeZero(this.module, global.type);
|
initExpr = typeToNativeZero(this.module, global.type);
|
||||||
} else
|
} else
|
||||||
throw new Error("unexpected missing declaration or constant value");
|
throw new Error("declaration expected");
|
||||||
|
|
||||||
const internalName: string = global.internalName;
|
const internalName: string = global.internalName;
|
||||||
if (initializeInStart) {
|
if (initializeInStart) {
|
||||||
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, global.type));
|
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, global.type));
|
||||||
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
|
const setExpr: ExpressionRef = this.module.createSetGlobal(internalName, initExpr);
|
||||||
|
if (!this.module.noEmit)
|
||||||
|
this.startFunctionBody.push(setExpr);
|
||||||
} else {
|
} else {
|
||||||
this.module.addGlobal(internalName, nativeType, global.isMutable, initializer);
|
this.module.addGlobal(internalName, nativeType, global.isMutable, initExpr);
|
||||||
if (!global.isMutable) {
|
if (!global.isMutable && !this.module.noEmit) {
|
||||||
const exprType: NativeType = _BinaryenExpressionGetType(initializer);
|
const exprType: NativeType = _BinaryenExpressionGetType(initExpr);
|
||||||
switch (exprType) {
|
switch (exprType) {
|
||||||
case NativeType.I32:
|
case NativeType.I32:
|
||||||
global.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initializer), 0);
|
global.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initExpr), 0);
|
||||||
break;
|
break;
|
||||||
case NativeType.I64:
|
case NativeType.I64:
|
||||||
global.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initializer), _BinaryenConstGetValueI64High(initializer));
|
global.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initExpr), _BinaryenConstGetValueI64High(initExpr));
|
||||||
break;
|
break;
|
||||||
case NativeType.F32:
|
case NativeType.F32:
|
||||||
global.constantFloatValue = _BinaryenConstGetValueF32(initializer);
|
global.constantFloatValue = _BinaryenConstGetValueF32(initExpr);
|
||||||
break;
|
break;
|
||||||
case NativeType.F64:
|
case NativeType.F64:
|
||||||
global.constantFloatValue = _BinaryenConstGetValueF64(initializer);
|
global.constantFloatValue = _BinaryenConstGetValueF64(initExpr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("unexpected initializer type");
|
throw new Error("concrete type expected");
|
||||||
}
|
}
|
||||||
global.hasConstantValue = true;
|
global.hasConstantValue = true;
|
||||||
}
|
}
|
||||||
@ -417,13 +428,14 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
compileEnumDeclaration(declaration: EnumDeclaration): void {
|
compileEnumDeclaration(declaration: EnumDeclaration): void {
|
||||||
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
|
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
|
||||||
if (!element || element.kind != ElementKind.ENUM)
|
if (!element || element.kind != ElementKind.ENUM)
|
||||||
throw new Error("unexpected missing enum");
|
throw new Error("enum expected");
|
||||||
this.compileEnum(<Enum>element);
|
this.compileEnum(<Enum>element);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileEnum(element: Enum): void {
|
compileEnum(element: Enum): void {
|
||||||
if (element.isCompiled)
|
if (element.isCompiled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let previousValue: EnumValue | null = null;
|
let previousValue: EnumValue | null = null;
|
||||||
if (element.members)
|
if (element.members)
|
||||||
for (let [key, member] of element.members) {
|
for (let [key, member] of element.members) {
|
||||||
@ -434,45 +446,49 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
|
this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
|
||||||
} else if (val.declaration) {
|
} else if (val.declaration) {
|
||||||
const declaration: EnumValueDeclaration = val.declaration;
|
const declaration: EnumValueDeclaration = val.declaration;
|
||||||
let initializer: ExpressionRef;
|
let initExpr: ExpressionRef;
|
||||||
let initializeInStart: bool = false;
|
let initInStart: bool = false;
|
||||||
if (declaration.value) {
|
if (declaration.value) {
|
||||||
initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
|
initExpr = this.compileExpression(<Expression>declaration.value, Type.i32);
|
||||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
if (!this.module.noEmit && _BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
|
||||||
initializer = this.precomputeExpressionRef(initializer);
|
initExpr = this.precomputeExpressionRef(initExpr);
|
||||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
|
||||||
if (element.isConstant)
|
if (element.isConstant)
|
||||||
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
||||||
initializeInStart = true;
|
initInStart = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (previousValue == null) {
|
} else if (previousValue == null) {
|
||||||
initializer = this.module.createI32(0);
|
initExpr = this.module.createI32(0);
|
||||||
} else if (previousValue.hasConstantValue) {
|
} else if (previousValue.hasConstantValue) {
|
||||||
initializer = this.module.createI32(previousValue.constantValue + 1);
|
initExpr = this.module.createI32(previousValue.constantValue + 1);
|
||||||
} else {
|
} else {
|
||||||
// in TypeScript this errors with TS1061, but actually we can do:
|
// in TypeScript this errors with TS1061, but actually we can do:
|
||||||
initializer = this.module.createBinary(BinaryOp.AddI32,
|
initExpr = this.module.createBinary(BinaryOp.AddI32,
|
||||||
this.module.createGetGlobal(previousValue.internalName, NativeType.I32),
|
this.module.createGetGlobal(previousValue.internalName, NativeType.I32),
|
||||||
this.module.createI32(1)
|
this.module.createI32(1)
|
||||||
);
|
);
|
||||||
if (element.isConstant)
|
if (element.isConstant)
|
||||||
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
||||||
initializeInStart = true;
|
initInStart = true;
|
||||||
}
|
}
|
||||||
if (initializeInStart) {
|
if (initInStart) {
|
||||||
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0));
|
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0));
|
||||||
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
|
const setExpr: ExpressionRef = this.module.createSetGlobal(val.internalName, initExpr);
|
||||||
|
if (!this.module.noEmit)
|
||||||
|
this.startFunctionBody.push(setExpr);
|
||||||
} else {
|
} else {
|
||||||
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
|
this.module.addGlobal(val.internalName, NativeType.I32, false, initExpr);
|
||||||
if (_BinaryenExpressionGetType(initializer) == NativeType.I32) {
|
if (!this.module.noEmit) {
|
||||||
val.constantValue = _BinaryenConstGetValueI32(initializer);
|
if (_BinaryenExpressionGetType(initExpr) == NativeType.I32) {
|
||||||
val.hasConstantValue = true;
|
val.constantValue = _BinaryenConstGetValueI32(initExpr);
|
||||||
} else
|
val.hasConstantValue = true;
|
||||||
throw new Error("unexpected initializer type");
|
} else
|
||||||
|
throw new Error("i32 expected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
throw new Error("unexpected missing declaration or constant value");
|
throw new Error("declaration expected");
|
||||||
previousValue = <EnumValue>val;
|
previousValue = <EnumValue>val;
|
||||||
}
|
}
|
||||||
element.isCompiled = true;
|
element.isCompiled = true;
|
||||||
@ -505,7 +521,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
const declaration: FunctionDeclaration | null = instance.prototype.declaration;
|
const declaration: FunctionDeclaration | null = instance.prototype.declaration;
|
||||||
if (!declaration)
|
if (!declaration)
|
||||||
throw new Error("unexpected missing declaration");
|
throw new Error("declaration expected"); // built-ins are not compiled here
|
||||||
|
|
||||||
if (instance.isDeclared) {
|
if (instance.isDeclared) {
|
||||||
if (declaration.statements) {
|
if (declaration.statements) {
|
||||||
@ -600,7 +616,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileNamespace(ns: Namespace): void {
|
compileNamespace(ns: Namespace): void {
|
||||||
if (!ns.members) return;
|
if (!ns.members)
|
||||||
|
return;
|
||||||
|
|
||||||
const noTreeShaking: bool = this.options.noTreeShaking;
|
const noTreeShaking: bool = this.options.noTreeShaking;
|
||||||
for (let [name, element] of ns.members) {
|
for (let [name, element] of ns.members) {
|
||||||
switch (element.kind) {
|
switch (element.kind) {
|
||||||
@ -714,20 +732,6 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// types
|
|
||||||
|
|
||||||
// TODO: try to get rid of this
|
|
||||||
determineExpressionType(expression: Expression, contextualType: Type = Type.void): Type {
|
|
||||||
const previousType: Type = this.currentType;
|
|
||||||
const previousNoEmit: bool = this.module.noEmit;
|
|
||||||
this.module.noEmit = true;
|
|
||||||
this.compileExpression(expression, contextualType, ConversionKind.NONE); // now performs a dry run
|
|
||||||
const type: Type = this.currentType;
|
|
||||||
this.currentType = previousType;
|
|
||||||
this.module.noEmit = previousNoEmit;
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
|
|
||||||
compileStatement(statement: Statement): ExpressionRef {
|
compileStatement(statement: Statement): ExpressionRef {
|
||||||
@ -785,11 +789,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileStatements(statements: Statement[]): ExpressionRef[] {
|
compileStatements(statements: Statement[]): ExpressionRef[] {
|
||||||
const k: i32 = statements.length;
|
let i: i32 = 0, k: i32 = statements.length;
|
||||||
const stmts: ExpressionRef[] = new Array(k);
|
const stmts: ExpressionRef[] = new Array(k);
|
||||||
for (let i: i32 = 0; i < k; ++i)
|
for (; i < k; ++i)
|
||||||
stmts[i] = this.compileStatement(statements[i]);
|
stmts[i] = this.compileStatement(statements[i]);
|
||||||
return stmts;
|
return stmts; // array of 0-es in noEmit-mode
|
||||||
}
|
}
|
||||||
|
|
||||||
compileBlockStatement(statement: BlockStatement): ExpressionRef {
|
compileBlockStatement(statement: BlockStatement): ExpressionRef {
|
||||||
@ -802,8 +806,10 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileBreakStatement(statement: BreakStatement): ExpressionRef {
|
compileBreakStatement(statement: BreakStatement): ExpressionRef {
|
||||||
if (statement.label)
|
if (statement.label) {
|
||||||
throw new Error("not implemented");
|
this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
}
|
||||||
const context: string | null = this.currentFunction.breakContext;
|
const context: string | null = this.currentFunction.breakContext;
|
||||||
if (context != null)
|
if (context != null)
|
||||||
return this.module.createBreak("break|" + (<string>context));
|
return this.module.createBreak("break|" + (<string>context));
|
||||||
@ -812,8 +818,10 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileContinueStatement(statement: ContinueStatement): ExpressionRef {
|
compileContinueStatement(statement: ContinueStatement): ExpressionRef {
|
||||||
if (statement.label)
|
if (statement.label) {
|
||||||
throw new Error("not implemented");
|
this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
}
|
||||||
const context: string | null = this.currentFunction.breakContext;
|
const context: string | null = this.currentFunction.breakContext;
|
||||||
if (context != null && !this.disallowContinue)
|
if (context != null && !this.disallowContinue)
|
||||||
return this.module.createBreak("continue|" + (<string>context));
|
return this.module.createBreak("continue|" + (<string>context));
|
||||||
@ -973,13 +981,16 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
const declaration: VariableDeclaration = declarations[i];
|
const declaration: VariableDeclaration = declarations[i];
|
||||||
const name: string = declaration.name.name;
|
const name: string = declaration.name.name;
|
||||||
let type: Type | null = null;
|
let type: Type | null = null;
|
||||||
|
let init: ExpressionRef = 0;
|
||||||
if (declaration.type) {
|
if (declaration.type) {
|
||||||
type = this.program.resolveType(<TypeNode>declaration.type, this.currentFunction.contextualTypeArguments, true); // reports
|
type = this.program.resolveType(<TypeNode>declaration.type, this.currentFunction.contextualTypeArguments, true); // reports
|
||||||
if (!type)
|
if (!type)
|
||||||
continue;
|
continue;
|
||||||
} else if (declaration.initializer) {
|
if (declaration.initializer)
|
||||||
type = this.determineExpressionType(declaration.initializer); // reports
|
init = this.compileExpression(declaration.initializer, type); // reports and returns unreachable
|
||||||
if (!type)
|
} else if (declaration.initializer) { // infer type
|
||||||
|
init = this.compileExpression(declaration.initializer, Type.void, ConversionKind.NONE); // reports and returns unreachable
|
||||||
|
if ((type = this.currentType) == Type.void)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd);
|
this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd);
|
||||||
@ -989,8 +1000,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); // recoverable
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); // recoverable
|
||||||
else {
|
else {
|
||||||
this.currentFunction.addLocal(type, name);
|
this.currentFunction.addLocal(type, name);
|
||||||
if (declaration.initializer)
|
if (init)
|
||||||
initializers.push(this.compileAssignment(declaration.name, <Expression>declaration.initializer, Type.void));
|
initializers.push(this.compileAssignmentWithValue(declaration.name, init));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop();
|
return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop();
|
||||||
@ -1600,8 +1611,35 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
|
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
|
||||||
this.currentType = this.determineExpressionType(expression, contextualType);
|
let element: Element | null = null;
|
||||||
return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType, ConversionKind.IMPLICIT), contextualType != Type.void);
|
switch (expression.kind) {
|
||||||
|
case NodeKind.IDENTIFIER:
|
||||||
|
element = this.program.resolveIdentifier(<IdentifierExpression>expression, this.currentFunction); // reports
|
||||||
|
break;
|
||||||
|
case NodeKind.PROPERTYACCESS:
|
||||||
|
element = this.program.resolvePropertyAccess(<PropertyAccessExpression>expression, this.currentFunction); // reports
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.error(DiagnosticCode.Operation_not_supported, expression.range);
|
||||||
|
}
|
||||||
|
if (!element)
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
let type: Type | null = null;
|
||||||
|
switch (element.kind) {
|
||||||
|
case ElementKind.LOCAL:
|
||||||
|
type = (<Local>element).type;
|
||||||
|
break;
|
||||||
|
case ElementKind.GLOBAL:
|
||||||
|
if (this.compileGlobal(<Global>element))
|
||||||
|
type = (<Global>element).type;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.error(DiagnosticCode.Operation_not_supported, expression.range);
|
||||||
|
}
|
||||||
|
if (!type)
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
this.currentType = type;
|
||||||
|
return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, type, ConversionKind.IMPLICIT), contextualType != Type.void);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileAssignmentWithValue(expression: Expression, valueWithCorrectType: ExpressionRef, tee: bool = false): ExpressionRef {
|
compileAssignmentWithValue(expression: Expression, valueWithCorrectType: ExpressionRef, tee: bool = false): ExpressionRef {
|
||||||
|
@ -1,11 +1,49 @@
|
|||||||
(module
|
(module
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $I (func (result i64)))
|
||||||
|
(type $f (func (result f32)))
|
||||||
|
(type $F (func (result f64)))
|
||||||
|
(global $infer-type/ri (mut i32) (i32.const 0))
|
||||||
|
(global $infer-type/rI (mut i64) (i64.const 0))
|
||||||
|
(global $infer-type/rf (mut f32) (f32.const 0))
|
||||||
|
(global $infer-type/rF (mut f64) (f64.const 0))
|
||||||
(memory $0 1)
|
(memory $0 1)
|
||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
(start $start)
|
(start $start)
|
||||||
(func $start (; 0 ;) (type $v)
|
(func $start (; 0 ;) (type $v)
|
||||||
(block $__inlined_func$infer-type/locals
|
(block
|
||||||
(nop)
|
(block $__inlined_func$infer-type/locals
|
||||||
|
(nop)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/ri
|
||||||
|
(block (result i32)
|
||||||
|
(block $__inlined_func$infer-type/reti (result i32)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rI
|
||||||
|
(block (result i64)
|
||||||
|
(block $__inlined_func$infer-type/retI (result i64)
|
||||||
|
(i64.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rf
|
||||||
|
(block (result f32)
|
||||||
|
(block $__inlined_func$infer-type/retf (result f32)
|
||||||
|
(f32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rF
|
||||||
|
(block (result f64)
|
||||||
|
(block $__inlined_func$infer-type/refF (result f64)
|
||||||
|
(f64.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,44 @@
|
|||||||
(module
|
(module
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $I (func (result i64)))
|
||||||
|
(type $f (func (result f32)))
|
||||||
|
(type $F (func (result f64)))
|
||||||
|
(global $infer-type/ri (mut i32) (i32.const 0))
|
||||||
|
(global $infer-type/rI (mut i64) (i64.const 0))
|
||||||
|
(global $infer-type/rf (mut f32) (f32.const 0))
|
||||||
|
(global $infer-type/rF (mut f64) (f64.const 0))
|
||||||
(memory $0 1)
|
(memory $0 1)
|
||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
(start $start)
|
(start $start)
|
||||||
(func $infer-type/locals (; 0 ;) (type $v)
|
(func $infer-type/locals (; 0 ;) (type $v)
|
||||||
(nop)
|
(nop)
|
||||||
)
|
)
|
||||||
(func $start (; 1 ;) (type $v)
|
(func $infer-type/reti (; 1 ;) (type $i) (result i32)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(func $infer-type/retI (; 2 ;) (type $I) (result i64)
|
||||||
|
(i64.const 0)
|
||||||
|
)
|
||||||
|
(func $infer-type/retf (; 3 ;) (type $f) (result f32)
|
||||||
|
(f32.const 0)
|
||||||
|
)
|
||||||
|
(func $infer-type/refF (; 4 ;) (type $F) (result f64)
|
||||||
|
(f64.const 0)
|
||||||
|
)
|
||||||
|
(func $start (; 5 ;) (type $v)
|
||||||
(call $infer-type/locals)
|
(call $infer-type/locals)
|
||||||
|
(set_global $infer-type/ri
|
||||||
|
(call $infer-type/reti)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rI
|
||||||
|
(call $infer-type/retI)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rf
|
||||||
|
(call $infer-type/retf)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rF
|
||||||
|
(call $infer-type/refF)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -16,3 +16,27 @@ function locals(): void {
|
|||||||
let aF = F;
|
let aF = F;
|
||||||
}
|
}
|
||||||
locals();
|
locals();
|
||||||
|
|
||||||
|
function reti(): i32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let ri = reti();
|
||||||
|
ri;
|
||||||
|
|
||||||
|
function retI(): i64 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let rI = retI();
|
||||||
|
rI;
|
||||||
|
|
||||||
|
function retf(): f32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let rf = retf();
|
||||||
|
rf;
|
||||||
|
|
||||||
|
function refF(): f64 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let rF = refF();
|
||||||
|
rF;
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
(module
|
(module
|
||||||
(type $v (func))
|
(type $v (func))
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $I (func (result i64)))
|
||||||
|
(type $f (func (result f32)))
|
||||||
|
(type $F (func (result f64)))
|
||||||
(global $infer-type/i i32 (i32.const 10))
|
(global $infer-type/i i32 (i32.const 10))
|
||||||
(global $infer-type/I i64 (i64.const 4294967296))
|
(global $infer-type/I i64 (i64.const 4294967296))
|
||||||
(global $infer-type/F f64 (f64.const 1.5))
|
(global $infer-type/F f64 (f64.const 1.5))
|
||||||
|
(global $infer-type/ri (mut i32) (i32.const 0))
|
||||||
|
(global $infer-type/rI (mut i64) (i64.const 0))
|
||||||
|
(global $infer-type/rf (mut f32) (f32.const 0))
|
||||||
|
(global $infer-type/rF (mut f64) (f64.const 0))
|
||||||
(global $HEAP_BASE i32 (i32.const 4))
|
(global $HEAP_BASE i32 (i32.const 4))
|
||||||
(memory $0 1)
|
(memory $0 1)
|
||||||
(export "memory" (memory $0))
|
(export "memory" (memory $0))
|
||||||
@ -45,7 +53,27 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(func $start (; 1 ;) (type $v)
|
(func $infer-type/reti (; 1 ;) (type $i) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $infer-type/retI (; 2 ;) (type $I) (result i64)
|
||||||
|
(return
|
||||||
|
(i64.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $infer-type/retf (; 3 ;) (type $f) (result f32)
|
||||||
|
(return
|
||||||
|
(f32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $infer-type/refF (; 4 ;) (type $F) (result f64)
|
||||||
|
(return
|
||||||
|
(f64.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 5 ;) (type $v)
|
||||||
(drop
|
(drop
|
||||||
(i32.const 10)
|
(i32.const 10)
|
||||||
)
|
)
|
||||||
@ -56,6 +84,30 @@
|
|||||||
(f64.const 1.5)
|
(f64.const 1.5)
|
||||||
)
|
)
|
||||||
(call $infer-type/locals)
|
(call $infer-type/locals)
|
||||||
|
(set_global $infer-type/ri
|
||||||
|
(call $infer-type/reti)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(get_global $infer-type/ri)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rI
|
||||||
|
(call $infer-type/retI)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(get_global $infer-type/rI)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rf
|
||||||
|
(call $infer-type/retf)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(get_global $infer-type/rf)
|
||||||
|
)
|
||||||
|
(set_global $infer-type/rF
|
||||||
|
(call $infer-type/refF)
|
||||||
|
)
|
||||||
|
(drop
|
||||||
|
(get_global $infer-type/rF)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(;
|
(;
|
||||||
@ -108,6 +160,14 @@
|
|||||||
infer-type/I
|
infer-type/I
|
||||||
infer-type/F
|
infer-type/F
|
||||||
infer-type/locals
|
infer-type/locals
|
||||||
|
infer-type/reti
|
||||||
|
infer-type/ri
|
||||||
|
infer-type/retI
|
||||||
|
infer-type/rI
|
||||||
|
infer-type/retf
|
||||||
|
infer-type/rf
|
||||||
|
infer-type/refF
|
||||||
|
infer-type/rF
|
||||||
[program.exports]
|
[program.exports]
|
||||||
|
|
||||||
;)
|
;)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user