Skip to content

Commit f9e6ce7

Browse files
authored
Implement typeof expressions (AssemblyScript#849)
1 parent bc6a944 commit f9e6ce7

File tree

6 files changed

+1221
-5
lines changed

6 files changed

+1221
-5
lines changed

src/compiler.ts

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8736,11 +8736,7 @@ export class Compiler extends DiagnosticEmitter {
87368736
break;
87378737
}
87388738
case Token.TYPEOF: {
8739-
this.error(
8740-
DiagnosticCode.Operation_not_supported,
8741-
expression.range
8742-
);
8743-
return module.unreachable();
8739+
return this.compileTypeof(expression, contextualType, constraints);
87448740
}
87458741
default: {
87468742
assert(false);
@@ -8761,6 +8757,88 @@ export class Compiler extends DiagnosticEmitter {
87618757
);
87628758
}
87638759

8760+
compileTypeof(
8761+
expression: UnaryPrefixExpression,
8762+
contextualType: Type,
8763+
constraints: Constraints
8764+
): ExpressionRef {
8765+
var operand = expression.operand;
8766+
var expr: ExpressionRef = 0;
8767+
var stringInstance = this.program.stringInstance;
8768+
var typeString: string;
8769+
if (operand.kind == NodeKind.NULL) {
8770+
typeString = "object"; // special since `null` without type context is usize
8771+
} else {
8772+
let element = this.resolver.lookupExpression(operand, this.currentFlow, Type.auto, ReportMode.SWALLOW);
8773+
if (!element) {
8774+
switch (operand.kind) {
8775+
case NodeKind.PROPERTYACCESS:
8776+
case NodeKind.ELEMENTACCESS: {
8777+
operand = operand.kind == NodeKind.PROPERTYACCESS
8778+
? (<PropertyAccessExpression>operand).expression
8779+
: (<ElementAccessExpression>operand).expression;
8780+
let targetType = this.resolver.resolveExpression(operand, this.currentFlow, Type.auto, ReportMode.REPORT);
8781+
if (!targetType) {
8782+
this.currentType = stringInstance.type;
8783+
return this.module.unreachable();
8784+
}
8785+
expr = this.compileExpression(operand, Type.auto); // might have side-effects
8786+
break;
8787+
}
8788+
case NodeKind.IDENTIFIER: break; // ignore error
8789+
default: expr = this.compileExpression(operand, Type.auto); // trigger error
8790+
}
8791+
typeString = "undefined";
8792+
} else {
8793+
switch (element.kind) {
8794+
case ElementKind.CLASS_PROTOTYPE:
8795+
case ElementKind.NAMESPACE:
8796+
case ElementKind.ENUM: {
8797+
typeString = "object";
8798+
break;
8799+
}
8800+
case ElementKind.FUNCTION_PROTOTYPE: {
8801+
typeString = "function";
8802+
break;
8803+
}
8804+
default: {
8805+
expr = this.compileExpression(operand, Type.auto);
8806+
let type = this.currentType;
8807+
expr = this.convertExpression(expr, type, Type.void, true, false, operand);
8808+
if (type.is(TypeFlags.REFERENCE)) {
8809+
let signatureReference = type.signatureReference;
8810+
if (signatureReference) {
8811+
typeString = "function";
8812+
} else {
8813+
let classReference = type.classReference;
8814+
if (classReference) {
8815+
if (classReference.prototype === stringInstance.prototype) {
8816+
typeString = "string";
8817+
} else {
8818+
typeString = "object";
8819+
}
8820+
} else {
8821+
typeString = "anyref"; // TODO?
8822+
}
8823+
}
8824+
} else if (type == Type.bool) {
8825+
typeString = "boolean";
8826+
} else if (type.isAny(TypeFlags.FLOAT | TypeFlags.INTEGER)) {
8827+
typeString = "number";
8828+
} else {
8829+
typeString = "undefined"; // failed to compile?
8830+
}
8831+
break;
8832+
}
8833+
}
8834+
}
8835+
}
8836+
this.currentType = stringInstance.type;
8837+
return expr
8838+
? this.module.block(null, [ expr, this.ensureStaticString(typeString) ], this.options.nativeSizeType)
8839+
: this.ensureStaticString(typeString);
8840+
}
8841+
87648842
/** Makes sure that a 32-bit integer value is wrapped to a valid value of the specified type. */
87658843
ensureSmallIntegerWrap(expr: ExpressionRef, type: Type): ExpressionRef {
87668844
var module = this.module;

src/resolver.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,14 @@ export class Resolver extends DiagnosticEmitter {
10631063
/** How to proceed with eventual diagnostics. */
10641064
reportMode: ReportMode = ReportMode.REPORT
10651065
): Element | null {
1066+
switch (node.kind) {
1067+
case NodeKind.TRUE:
1068+
case NodeKind.FALSE:
1069+
case NodeKind.NULL: {
1070+
let type = this.resolveIdentifierExpression(node, ctxFlow, Type.auto, ctxElement, reportMode);
1071+
return type ? this.getElementOfType(type) : null;
1072+
}
1073+
}
10661074
var name = node.text;
10671075
var element: Element | null;
10681076
if (element = ctxFlow.lookup(name)) {

tests/compiler/typeof.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"asc_flags": [
3+
"--runtime none",
4+
"--explicitStart"
5+
]
6+
}

0 commit comments

Comments
 (0)