Skip to content

Commit ae99ade

Browse files
committed
Better resolve infrastructure; Instance fields
1 parent fb2b7aa commit ae99ade

17 files changed

+1425
-315
lines changed

src/compiler.ts

+165-254
Large diffs are not rendered by default.

src/module.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -496,24 +496,24 @@ export class Module {
496496
}
497497
}
498498

499-
createCall(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef {
499+
createCall(target: string, operands: ExpressionRef[] | null, returnType: NativeType): ExpressionRef {
500500
if (this.noEmit) return 0;
501501
var cStr = allocString(target);
502502
var cArr = allocI32Array(operands);
503503
try {
504-
return _BinaryenCall(this.ref, cStr, cArr, operands.length, returnType);
504+
return _BinaryenCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
505505
} finally {
506506
Heap.dispose(cArr);
507507
Heap.dispose(cStr);
508508
}
509509
}
510510

511-
createCallImport(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef {
511+
createCallImport(target: string, operands: ExpressionRef[] | null, returnType: NativeType): ExpressionRef {
512512
if (this.noEmit) return 0;
513513
var cStr = allocString(target);
514514
var cArr = allocI32Array(operands);
515515
try {
516-
return _BinaryenCallImport(this.ref, cStr, cArr, operands.length, returnType);
516+
return _BinaryenCallImport(this.ref, cStr, cArr, operands && operands.length || 0, returnType);
517517
} finally {
518518
Heap.dispose(cArr);
519519
Heap.dispose(cStr);

src/program.ts

+88-48
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ import {
6767

6868
hasDecorator,
6969
hasModifier,
70-
mangleInternalName
70+
mangleInternalName,
71+
ElementAccessExpression,
72+
ThisExpression,
73+
SuperExpression
7174
} from "./ast";
7275

7376
import {
@@ -896,11 +899,11 @@ export class Program extends DiagnosticEmitter {
896899
}
897900

898901
/** Resolves an identifier to the element it refers to. */
899-
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function): Element | null {
902+
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function): ResolvedElement | null {
900903
var name = identifier.name;
901904
var local = contextualFunction.locals.get(name);
902905
if (local)
903-
return local;
906+
return resolvedElement.set(local);
904907

905908
var element: Element | null;
906909
var namespace: Element | null;
@@ -909,96 +912,131 @@ export class Program extends DiagnosticEmitter {
909912
if (contextualFunction && (namespace = contextualFunction.prototype.namespace)) {
910913
do {
911914
if (element = this.elements.get(namespace.internalName + STATIC_DELIMITER + name))
912-
return element;
915+
return resolvedElement.set(element);
913916
} while (namespace = namespace.namespace);
914917
}
915918

916919
// search current file
917920
if (element = this.elements.get(identifier.range.source.internalPath + PATH_DELIMITER + name))
918-
return element;
921+
return resolvedElement.set(element);
919922

920923
// search global scope
921924
if (element = this.elements.get(name))
922-
return element;
925+
return resolvedElement.set(element);
923926

924927
this.error(DiagnosticCode.Cannot_find_name_0, identifier.range, name);
925928
return null;
926929
}
927930

928931
/** Resolves a property access to the element it refers to. */
929-
resolvePropertyAccess(propertyAccess: PropertyAccessExpression, contextualFunction: Function): Element | null {
930-
var expression = propertyAccess.expression;
931-
var target: Element | null = null;
932-
switch (expression.kind) {
933-
934-
case NodeKind.IDENTIFIER:
935-
target = this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
936-
break;
937-
938-
case NodeKind.PROPERTYACCESS:
939-
target = this.resolvePropertyAccess(<PropertyAccessExpression>expression, contextualFunction);
940-
break;
941-
942-
// case NodeKind.ELEMENTACCESS:
932+
resolvePropertyAccess(propertyAccess: PropertyAccessExpression, contextualFunction: Function): ResolvedElement | null {
933+
var resolved: ResolvedElement | null;
943934

944-
default:
945-
throw new Error("property target expected");
946-
}
947-
if (!target)
935+
// start by resolving the lhs target (expression before the last dot)
936+
var targetExpression = propertyAccess.expression;
937+
if (!(resolved = this.resolveExpression(targetExpression, contextualFunction)))
948938
return null;
939+
var target = resolved.element;
949940

941+
// at this point we know exactly what the target is, so look up the element within
950942
var propertyName = propertyAccess.property.name;
943+
var targetType: Type | null;
951944
switch (target.kind) {
952945

953946
case ElementKind.GLOBAL:
954947
case ElementKind.LOCAL:
955-
var type = (<VariableLikeElement>target).type;
956-
assert(type != null); // locals don't have lazy types, unlike globals
957-
if ((<Type>type).classType) {
958-
target = <Class>(<Type>type).classType;
948+
targetType = (<VariableLikeElement>target).type;
949+
if (!targetType) // FIXME: are globals always resolved here?
950+
throw new Error("type expected");
951+
if (targetType.classType)
952+
target = targetType.classType;
959953
// fall-through
960-
} else
954+
else
961955
break;
962956

963957
default:
964958
if (target.members) {
965959
var member = target.members.get(propertyName);
966960
if (member)
967-
return member;
961+
return resolvedElement.set(member).withTarget(target, targetExpression);
968962
}
969963
break;
970964
}
971-
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyAccess.property.name, target.internalName);
965+
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, target.internalName);
972966
return null;
973967
}
974968

975-
resolveElement(expression: Expression, contextualFunction: Function): Element | null {
969+
resolveElementAccess(elementAccess: ElementAccessExpression, contextualFunction: Function): ResolvedElement | null {
970+
var resolved: ResolvedElement | null;
976971

977-
// this -> Class
978-
if (expression.kind == NodeKind.THIS) {
979-
if (contextualFunction.instanceMethodOf)
980-
return contextualFunction.instanceMethodOf;
981-
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
972+
// start by resolving the lhs target (expression before the last dot)
973+
var targetExpression = elementAccess.expression;
974+
if (!(resolved = this.resolveExpression(targetExpression, contextualFunction)))
982975
return null;
983-
}
976+
var target = resolved.element;
977+
978+
// at this point we know exactly what the target is, so make sure it is an array and look up the element within
979+
throw new Error("not implemented");
980+
}
984981

985-
// local or global name
986-
if (expression.kind == NodeKind.IDENTIFIER) {
987-
return this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
982+
resolveExpression(expression: Expression, contextualFunction: Function): ResolvedElement | null {
983+
var classType: Class | null;
984+
switch (expression.kind) {
988985

989-
// static or instance property (incl. enum values) or method
990-
} else if (expression.kind == NodeKind.PROPERTYACCESS) {
991-
return this.resolvePropertyAccess(<PropertyAccessExpression>expression, contextualFunction);
986+
case NodeKind.THIS: // -> Class
987+
if (classType = contextualFunction.instanceMethodOf)
988+
return resolvedElement.set(classType);
989+
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
990+
return null;
991+
992+
case NodeKind.SUPER: // -> Class
993+
if ((classType = contextualFunction.instanceMethodOf) && (classType = classType.base))
994+
return resolvedElement.set(classType);
995+
this.error(DiagnosticCode._super_can_only_be_referenced_in_a_derived_class, expression.range);
996+
return null;
992997

993-
// instantiation
994-
} else if (expression.kind == NodeKind.NEW) {
995-
return this.resolveElement((<NewExpression>expression).expression, contextualFunction);
998+
case NodeKind.IDENTIFIER:
999+
return this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
1000+
1001+
case NodeKind.PROPERTYACCESS:
1002+
return this.resolvePropertyAccess(<PropertyAccessExpression>expression, contextualFunction);
1003+
1004+
case NodeKind.ELEMENTACCESS:
1005+
return this.resolveElementAccess(<ElementAccessExpression>expression, contextualFunction);
1006+
1007+
default:
1008+
this.error(DiagnosticCode.Operation_not_supported, expression.range);
1009+
return null;
9961010
}
1011+
}
1012+
}
9971013

998-
throw new Error("not implemented");
1014+
/** Common result structure returned when calling any of the resolve functions on a {@link Program}. */
1015+
export class ResolvedElement {
1016+
1017+
/** The target element, if a property or element access */
1018+
target: Element | null;
1019+
/** The target element's sub-expression, if a property or element access. */
1020+
targetExpression: Expression | null;
1021+
/** The element being accessed. */
1022+
element: Element;
1023+
1024+
set(element: Element): this {
1025+
this.target = null;
1026+
this.targetExpression = null;
1027+
this.element = element;
1028+
return this;
1029+
}
1030+
1031+
withTarget(target: Element, targetExpression: Expression): this {
1032+
this.target = target;
1033+
this.targetExpression = targetExpression;
1034+
return this;
9991035
}
10001036
}
10011037

1038+
var resolvedElement = new ResolvedElement();
1039+
10021040
/** Indicates the specific kind of an {@link Element}. */
10031041
export enum ElementKind {
10041042
/** A {@link Global}. */
@@ -1288,6 +1326,7 @@ export class Local extends VariableLikeElement {
12881326

12891327
kind = ElementKind.LOCAL;
12901328

1329+
type: Type; // more specific
12911330
/** Local index. */
12921331
index: i32;
12931332

@@ -1685,6 +1724,7 @@ export class Field extends Element {
16851724
/** Constructs a new field. */
16861725
constructor(prototype: FieldPrototype, internalName: string, type: Type) {
16871726
super(prototype.program, prototype.simpleName, internalName);
1727+
this.prototype = prototype;
16881728
this.flags = prototype.flags;
16891729
this.type = type;
16901730
}

tests/compiler.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
5858
module.interpret();
5959
console.log(chalk.default.green("interpret OK"));
6060
try {
61-
var wasmModule = new WebAssembly.Module(module.toBinary());
61+
var binary = module.toBinary();
62+
var wasmModule = new WebAssembly.Module(binary);
6263
var wasmInstance = new WebAssembly.Instance(wasmModule, {
6364
env: {
6465
externalFunc: function() {},

tests/compiler/class.optimized-inlined.wast

+27
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,33 @@
6363
)
6464
)
6565
)
66+
(drop
67+
(i32.load
68+
(get_local $0)
69+
)
70+
)
71+
(drop
72+
(i32.load16_s offset=4
73+
(get_local $0)
74+
)
75+
)
76+
(drop
77+
(i32.load8_s offset=6
78+
(get_local $0)
79+
)
80+
)
81+
(i32.store
82+
(get_local $0)
83+
(i32.const 1)
84+
)
85+
(i32.store16 offset=4
86+
(get_local $0)
87+
(i32.const 2)
88+
)
89+
(i32.store8 offset=6
90+
(get_local $0)
91+
(i32.const 3)
92+
)
6693
(get_local $0)
6794
)
6895
(func $start (; 1 ;) (type $v)

tests/compiler/class.optimized.wast

+27
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,33 @@
6565
(f32.const 2)
6666
)
6767
)
68+
(drop
69+
(i32.load
70+
(get_local $0)
71+
)
72+
)
73+
(drop
74+
(i32.load16_s offset=4
75+
(get_local $0)
76+
)
77+
)
78+
(drop
79+
(i32.load8_s offset=6
80+
(get_local $0)
81+
)
82+
)
83+
(i32.store
84+
(get_local $0)
85+
(i32.const 1)
86+
)
87+
(i32.store16 offset=4
88+
(get_local $0)
89+
(i32.const 2)
90+
)
91+
(i32.store8 offset=6
92+
(get_local $0)
93+
(i32.const 3)
94+
)
6895
(get_local $0)
6996
)
7097
(func $start (; 5 ;) (type $v)

tests/compiler/class.ts

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ export function test(animal: Animal<f64>): Animal<f64> {
2020
animal.instanceAdd(1, 2);
2121
animal.instanceSub<f32>(1, 2);
2222

23+
animal.one;
24+
animal.two;
25+
animal.three;
26+
27+
animal.one = 0 + 1;
28+
animal.two = 1 + 1;
29+
animal.three = 1 + 1 + 1;
30+
2331
var ptr = changetype<usize>(animal);
2432
var cls = changetype<Animal<f64>>(ptr);
2533
return cls;

tests/compiler/class.wast

+39
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,45 @@
7676
(f32.const 2)
7777
)
7878
)
79+
(drop
80+
(i32.load
81+
(get_local $0)
82+
)
83+
)
84+
(drop
85+
(i32.load16_s offset=4
86+
(get_local $0)
87+
)
88+
)
89+
(drop
90+
(i32.load8_s offset=6
91+
(get_local $0)
92+
)
93+
)
94+
(i32.store
95+
(get_local $0)
96+
(i32.add
97+
(i32.const 0)
98+
(i32.const 1)
99+
)
100+
)
101+
(i32.store16 offset=4
102+
(get_local $0)
103+
(i32.add
104+
(i32.const 1)
105+
(i32.const 1)
106+
)
107+
)
108+
(i32.store8 offset=6
109+
(get_local $0)
110+
(i32.add
111+
(i32.add
112+
(i32.const 1)
113+
(i32.const 1)
114+
)
115+
(i32.const 1)
116+
)
117+
)
79118
(block
80119
(set_local $1
81120
(get_local $0)

tests/compiler/empty.optimized.wast

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(module
2+
(memory $0 1)
3+
(export "memory" (memory $0))
4+
)

tests/compiler/empty.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)