Foundation for IndexStore/IndexLoad (no lowering)
Adds new types for IndexLoad/IndexStore (renamed later in the stack to ComputedLoad/ComputedStore) which will be used to represent computed property access/update. The actual lowering to use these is later in the stack.
Joe Savona committed
Jan 3, 2023 at 16:59 UTC
45b3bd48991772df7d014bcfde60e183074dc25b
7 files changed
+99
compiler/forget/src/HIR/Codegen.ts
+20
@@ -473,6 +473,26 @@ export function codegenInstructionValue(
473
);
474
break;
475
}
476
+ case "IndexStore": {
477
+ value = t.assignmentExpression(
478
+ "=",
479
+ t.memberExpression(
480
+ codegenPlace(temp, instrValue.object),
481
+ codegenPlace(temp, instrValue.property),
482
+ true
483
+ ),
484
+ codegenPlace(temp, instrValue.value)
485
+ );
486
+ break;
487
+ }
488
+ case "IndexLoad": {
489
+ value = t.memberExpression(
490
+ codegenPlace(temp, instrValue.object),
491
+ codegenPlace(temp, instrValue.property),
492
+ true
493
+ );
494
+ break;
495
+ }
496
case "Identifier": {
497
value = codegenPlace(temp, instrValue);
498
break;
compiler/forget/src/HIR/HIR.ts
+5
@@ -298,6 +298,11 @@ export type InstructionData =
298
// load `object.property`
299
| { kind: "PropertyLoad"; object: Place; property: string }
300
301
+ // store `object[index] = value` - like PropertyStore but with a dynamic property
302
+ | { kind: "IndexStore"; object: Place; property: Place; value: Place }
303
+ // load `object[index]` - like PropertyLoad but with a dynamic property
304
+ | { kind: "IndexLoad"; object: Place; property: Place }
305
+
306
/**
307
* Catch-all for statements such as type imports, nested class declarations, etc
308
* which are not directly represented, but included for completeness and to allow
compiler/forget/src/HIR/InferReferenceEffects.ts
+36
@@ -607,6 +607,42 @@ function inferBlock(env: Environment, block: BasicBlock) {
607
}
608
continue;
609
}
610
+ case "IndexStore": {
611
+ const effect = isObjectType(instrValue.object.identifier)
612
+ ? Effect.Store
613
+ : Effect.Mutate;
614
+ env.reference(instrValue.value, Effect.Read);
615
+ env.reference(instrValue.property, Effect.Read);
616
+ env.reference(instrValue.object, effect);
617
+
618
+ const lvalue = instr.lvalue;
619
+ if (lvalue !== null) {
620
+ env.alias(lvalue.place, instrValue.value);
621
+ lvalue.place.effect = Effect.Store;
622
+ }
623
+ continue;
624
+ }
625
+ case "IndexLoad": {
626
+ if (!env.isDefined(instrValue.object)) {
627
+ // TODO @josephsavona: improve handling of globals
628
+ const value: InstructionValue = {
629
+ kind: "Primitive",
630
+ loc: instrValue.loc,
631
+ value: undefined,
632
+ };
633
+ env.initialize(value, ValueKind.Frozen);
634
+ env.define(instrValue.object, value);
635
+ }
636
+
637
+ env.reference(instrValue.object, Effect.Read);
638
+ env.reference(instrValue.property, Effect.Read);
639
+ const lvalue = instr.lvalue;
640
+ if (lvalue !== null) {
641
+ env.initialize(instrValue, env.kind(instrValue.object));
642
+ env.define(lvalue.place, instrValue);
643
+ }
644
+ continue;
645
+ }
646
case "Identifier": {
647
env.reference(instrValue, Effect.Read);
648
const lvalue = instr.lvalue;
compiler/forget/src/HIR/PrintHIR.ts
+12
@@ -277,6 +277,18 @@ export function printInstructionValue(instrValue: InstructionValue): string {
277
} = ${printPlace(instrValue.value)}`;
278
break;
279
}
280
+ case "IndexLoad": {
281
+ value = `IndexLoad ${printPlace(instrValue.object)}[${printPlace(
282
+ instrValue.property
283
+ )}]`;
284
+ break;
285
+ }
286
+ case "IndexStore": {
287
+ value = `IndexStore ${printPlace(instrValue.object)}[${printPlace(
288
+ instrValue.property
289
+ )}] = ${printPlace(instrValue.value)}`;
290
+ break;
291
+ }
292
default: {
293
assertExhaustive(
294
instrValue,
compiler/forget/src/HIR/visitors.ts
+22
@@ -50,6 +50,17 @@ export function* eachInstructionValueOperand(
50
yield instrValue.value;
51
break;
52
}
53
+ case "IndexLoad": {
54
+ yield instrValue.object;
55
+ yield instrValue.property;
56
+ break;
57
+ }
58
+ case "IndexStore": {
59
+ yield instrValue.object;
60
+ yield instrValue.property;
61
+ yield instrValue.value;
62
+ break;
63
+ }
64
case "UnaryExpression": {
65
yield instrValue.value;
66
break;
@@ -110,6 +121,17 @@ export function mapInstructionOperands(
121
instrValue.value = fn(instrValue.value);
122
break;
123
}
124
+ case "IndexLoad": {
125
+ instrValue.object = fn(instrValue.object);
126
+ instrValue.property = fn(instrValue.property);
127
+ break;
128
+ }
129
+ case "IndexStore": {
130
+ instrValue.object = fn(instrValue.object);
131
+ instrValue.property = fn(instrValue.property);
132
+ instrValue.value = fn(instrValue.value);
133
+ break;
134
+ }
135
case "Identifier": {
136
instr.value = fn(instrValue);
137
break;
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+2
@@ -161,11 +161,13 @@ function mayAllocate(value: InstructionValue): boolean {
161
case "BinaryExpression":
162
case "Identifier":
163
case "PropertyLoad":
164
+ case "IndexLoad":
165
case "JSXText":
166
case "Primitive": {
167
return false;
168
}
169
case "PropertyStore":
170
+ case "IndexStore":
171
case "ArrayExpression":
172
case "CallExpression":
173
case "JsxExpression":
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+2
@@ -302,6 +302,8 @@ function valueKind(value: InstructionValue): DeclKind {
302
case "Primitive": {
303
return DeclKind.Const;
304
}
305
+ case "IndexLoad":
306
+ case "IndexStore":
307
case "PropertyStore":
308
case "PropertyLoad":
309
case "Identifier":