Skip to content

Commit

Permalink
Add 'instantiate<T>' builtin (like 'new' but from a type), see #349
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO committed Nov 29, 2018
1 parent 1d93877 commit 1149abf
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 5 deletions.
19 changes: 19 additions & 0 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
18 changes: 13 additions & 5 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions std/assembly/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
@builtin export declare function assert<T>(isTrueish: T, message?: string): T;
@builtin export declare function unchecked<T>(expr: T): T;
@builtin export declare function call_indirect<T>(target: void, ...args: void[]): T;
@builtin export declare function instantiate<T>(...args: void[]): T;

@builtin export declare function i8(value: void): i8;
export namespace i8 {
Expand Down
2 changes: 2 additions & 0 deletions std/assembly/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ declare function changetype<T>(value: any): T;
declare function unchecked<T>(value: T): T;
/** Emits a `call_indirect` instruction, calling the specified function in the function table by index with the specified arguments. Does result in a runtime error if the arguments do not match the called function. */
declare function call_indirect<T>(target: Function | u32, ...args: any[]): T;
/** Instantiates a new instance of `T` using the specified constructor arguments. */
declare function instantiate<T>(...args: any[]): T;
/** Tests if a 32-bit or 64-bit float is `NaN`. */
declare function isNaN<T = f32 | f64>(value: T): bool;
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */
Expand Down

0 comments on commit 1149abf

Please sign in to comment.