Skip to content

Commit 7478c8a

Browse files
committed
Initial implementation of 'instanceof'
Works like an assignability check for now / does not yet honor nullables.
1 parent cea69a6 commit 7478c8a

File tree

9 files changed

+472
-4
lines changed

9 files changed

+472
-4
lines changed

dist/assemblyscript.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/assemblyscript.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ast.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export enum NodeKind {
4545
ELEMENTACCESS,
4646
FALSE,
4747
FUNCTION,
48+
INSTANCEOF,
4849
LITERAL,
4950
NEW,
5051
NULL,
@@ -346,6 +347,18 @@ export abstract class Node {
346347
return expr;
347348
}
348349

350+
static createInstanceOfExpression(
351+
expression: Expression,
352+
isType: CommonTypeNode,
353+
range: Range
354+
): InstanceOfExpression {
355+
var expr = new InstanceOfExpression();
356+
expr.range = range;
357+
expr.expression = expression; expression.parent = expr;
358+
expr.isType = isType; isType.parent = expr;
359+
return expr;
360+
}
361+
349362
static createIntegerLiteralExpression(
350363
value: I64,
351364
range: Range
@@ -1267,6 +1280,16 @@ export class FunctionExpression extends Expression {
12671280
declaration: FunctionDeclaration;
12681281
}
12691282

1283+
/** Represents an `instanceof` expression. */
1284+
export class InstanceOfExpression extends Expression {
1285+
kind = NodeKind.INSTANCEOF;
1286+
1287+
/** Expression being asserted. */
1288+
expression: Expression;
1289+
/** Type to test for. */
1290+
isType: CommonTypeNode;
1291+
}
1292+
12701293
/** Represents an integer literal expression. */
12711294
export class IntegerLiteralExpression extends LiteralExpression {
12721295
literalKind = LiteralKind.INTEGER;

src/compiler.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import {
9494
ForStatement,
9595
IfStatement,
9696
ImportStatement,
97+
InstanceOfExpression,
9798
InterfaceDeclaration,
9899
NamespaceDeclaration,
99100
ReturnStatement,
@@ -2263,6 +2264,10 @@ export class Compiler extends DiagnosticEmitter {
22632264
);
22642265
break;
22652266
}
2267+
case NodeKind.INSTANCEOF: {
2268+
expr = this.compileInstanceOfExpression(<InstanceOfExpression>expression, contextualType);
2269+
break;
2270+
}
22662271
case NodeKind.LITERAL: {
22672272
expr = this.compileLiteralExpression(<LiteralExpression>expression, contextualType);
22682273
break;
@@ -5873,6 +5878,18 @@ export class Compiler extends DiagnosticEmitter {
58735878
return this.module.createUnreachable();
58745879
}
58755880

5881+
compileInstanceOfExpression(
5882+
expression: InstanceOfExpression,
5883+
contextualType: Type
5884+
): ExpressionRef {
5885+
this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
5886+
var type = this.currentType;
5887+
var isType = this.program.resolveType(expression.isType);
5888+
this.currentType = Type.bool;
5889+
if (!isType) return this.module.createUnreachable();
5890+
return this.module.createI32(type.isAssignableTo(isType, false) ? 1 : 0);
5891+
}
5892+
58765893
compileLiteralExpression(
58775894
expression: LiteralExpression,
58785895
contextualType: Type,

src/extra/ast.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
ForStatement,
5353
IfStatement,
5454
ImportStatement,
55+
InstanceOfExpression,
5556
ReturnStatement,
5657
SwitchStatement,
5758
ThrowStatement,
@@ -160,6 +161,10 @@ export class ASTBuilder {
160161
this.visitFunctionExpression(<FunctionExpression>node);
161162
break;
162163
}
164+
case NodeKind.INSTANCEOF: {
165+
this.visitInstanceOfExpression(<InstanceOfExpression>node);
166+
break;
167+
}
163168
case NodeKind.LITERAL: {
164169
this.visitLiteralExpression(<LiteralExpression>node);
165170
break;
@@ -544,6 +549,12 @@ export class ASTBuilder {
544549
this.sb.push(node.value.toString(10));
545550
}
546551

552+
visitInstanceOfExpression(node: InstanceOfExpression): void {
553+
this.visitNode(node.expression);
554+
this.sb.push(" instanceof ");
555+
this.visitTypeNode(node.isType);
556+
}
557+
547558
visitIntegerLiteralExpression(node: IntegerLiteralExpression): void {
548559
this.sb.push(i64_to_string(node.value));
549560
}

src/parser.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,7 +3108,7 @@ export class Parser extends DiagnosticEmitter {
31083108
switch (token) {
31093109
// AssertionExpression
31103110
case Token.AS: {
3111-
let toType = this.parseType(tn);
3111+
let toType = this.parseType(tn); // reports
31123112
if (!toType) return null;
31133113
expr = Node.createAssertionExpression(
31143114
AssertionKind.AS,
@@ -3118,9 +3118,20 @@ export class Parser extends DiagnosticEmitter {
31183118
);
31193119
break;
31203120
}
3121+
// InstanceOfExpression
3122+
case Token.INSTANCEOF: {
3123+
let isType = this.parseType(tn); // reports
3124+
if (!isType) return null;
3125+
expr = Node.createInstanceOfExpression(
3126+
expr,
3127+
isType,
3128+
tn.range(startPos, tn.pos)
3129+
);
3130+
break;
3131+
}
31213132
// ElementAccessExpression
31223133
case Token.OPENBRACKET: {
3123-
next = this.parseExpression(tn);
3134+
next = this.parseExpression(tn); // reports
31243135
if (!next) return null;
31253136
if (!tn.skip(Token.CLOSEBRACKET)) {
31263137
this.error(
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
(module
2+
(type $iiiiv (func (param i32 i32 i32 i32)))
3+
(type $ii (func (param i32) (result i32)))
4+
(type $Fi (func (param f64) (result i32)))
5+
(type $v (func))
6+
(import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
7+
(memory $0 1)
8+
(data (i32.const 8) "\0d\00\00\00i\00n\00s\00t\00a\00n\00c\00e\00o\00f\00.\00t\00s")
9+
(export "memory" (memory $0))
10+
(start $start)
11+
(func $instanceof/isI32<i32> (; 1 ;) (type $ii) (param $0 i32) (result i32)
12+
(i32.const 1)
13+
)
14+
(func $instanceof/isI32<f64> (; 2 ;) (type $Fi) (param $0 f64) (result i32)
15+
(i32.const 0)
16+
)
17+
(func $start (; 3 ;) (type $v)
18+
(if
19+
(i32.eqz
20+
(call $instanceof/isI32<i32>
21+
(i32.const 0)
22+
)
23+
)
24+
(block
25+
(call $~lib/env/abort
26+
(i32.const 0)
27+
(i32.const 8)
28+
(i32.const 38)
29+
(i32.const 0)
30+
)
31+
(unreachable)
32+
)
33+
)
34+
(if
35+
(call $instanceof/isI32<f64>
36+
(f64.const 0)
37+
)
38+
(block
39+
(call $~lib/env/abort
40+
(i32.const 0)
41+
(i32.const 8)
42+
(i32.const 39)
43+
(i32.const 0)
44+
)
45+
(unreachable)
46+
)
47+
)
48+
)
49+
)

tests/compiler/instanceof.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
class A {}
2+
class B extends A {}
3+
4+
var a: A;
5+
var b: B;
6+
var i: i32;
7+
var f: f32;
8+
9+
assert( a instanceof A );
10+
assert( b instanceof A );
11+
assert(!(i instanceof A));
12+
assert(!(f instanceof A));
13+
14+
assert(!(a instanceof B));
15+
assert( b instanceof B );
16+
assert(!(i instanceof B));
17+
assert(!(f instanceof B));
18+
19+
assert(!(a instanceof i32));
20+
assert(!(b instanceof i32));
21+
assert( i instanceof i32 );
22+
assert(!(f instanceof i32));
23+
24+
assert(!(a instanceof f32));
25+
assert(!(b instanceof f32));
26+
assert(!(i instanceof f32));
27+
assert( f instanceof f32 );
28+
29+
function isI32<T>(v: T): bool {
30+
// should eliminate non-applicable branches (see fixture)
31+
if (v instanceof i32) {
32+
return true;
33+
} else {
34+
return false;
35+
}
36+
}
37+
38+
assert( isI32(0));
39+
assert(!isI32(0.0));
40+
41+
// TODO: what about nullables?
42+
// var an: A | null;
43+
// var bn: B | null;
44+
//
45+
// assert(an instanceof A);
46+
// assert(bn instanceof A);
47+
//
48+
// assert(!(an instanceof B));
49+
// assert(bn instanceof B);

0 commit comments

Comments
 (0)