Add 'instantiate<T>' builtin (like 'new' but from a type), see #349

This commit is contained in:
dcodeIO
2018-11-29 15:28:08 +01:00
parent 1d93877e7c
commit 1149abf824
4 changed files with 35 additions and 5 deletions

View File

@ -2322,6 +2322,25 @@ export function compileCall(
// thus must be used with care. it exists because it *might* be useful in specific scenarios.
return module.createCallIndirect(arg0, operandExprs, typeName);
}
case "instantiate": {
if (!(typeArguments && typeArguments.length == 1)) {
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
);
return module.createUnreachable();
}
let classInstance = typeArguments[0].classReference;
if (!classInstance) {
compiler.error(
DiagnosticCode.Operation_not_supported,
reportNode.range
);
return module.createUnreachable();
}
return compiler.compileInstantiate(classInstance, operands, reportNode);
}
// user-defined diagnostic macros

View File

@ -6651,9 +6651,10 @@ export class Compiler extends DiagnosticEmitter {
);
}
if (!classInstance) return module.createUnreachable();
return this.compileInstantiate(classInstance, expression.arguments, expression);
}
var expr: ExpressionRef;
compileInstantiate(classInstance: Class, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
// traverse to the top-most visible constructor
var currentClassInstance: Class | null = classInstance;
var constructorInstance: Function | null = null;
@ -6663,14 +6664,21 @@ export class Compiler extends DiagnosticEmitter {
} while (currentClassInstance = currentClassInstance.base);
// if a constructor is present, call it with a zero `this`
var expr: ExpressionRef;
if (constructorInstance) {
expr = this.compileCallDirect(constructorInstance, expression.arguments, expression,
options.usizeType.toNativeZero(module)
expr = this.compileCallDirect(constructorInstance, argumentExpressions, reportNode,
this.options.usizeType.toNativeZero(this.module)
);
// otherwise simply allocate a new instance and initialize its fields
} else {
expr = this.makeAllocate(classInstance, expression);
if (argumentExpressions.length) {
this.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "0", argumentExpressions.length.toString(10)
);
}
expr = this.makeAllocate(classInstance, reportNode);
}
this.currentType = classInstance.type;