Skip to content

Commit e9ca0f6

Browse files
committed
Factor out infix op evaluation
1 parent bf22dd3 commit e9ca0f6

3 files changed

Lines changed: 354 additions & 272 deletions

File tree

src/runtime/evaluate.ts

Lines changed: 10 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ import {
3333
ifStatementElseBlock,
3434
indexingExprArrayExpr,
3535
indexingExprIndexExpr,
36-
infixOpExprLhs,
3736
infixOpExprOpName,
38-
infixOpExprRhs,
3937
intLitExprValue,
4038
isBlock,
4139
isEmptyPlaceholder,
@@ -70,7 +68,6 @@ import {
7068
} from "./boolify";
7169
import {
7270
ArrayElementCell,
73-
assign,
7471
Cell,
7572
VarCell,
7673
} from "./cell";
@@ -90,7 +87,6 @@ import {
9087
import {
9188
E000_InternalError,
9289
E500_OutOfFuel,
93-
E601_ZeroDivisionError,
9490
E603_TypeError,
9591
E604_IndexError,
9692
E607_CannotAssignError,
@@ -103,6 +99,7 @@ import {
10399
E614_MacroAtRuntimeError,
104100
} from "./error";
105101
import {
102+
assertNotAssignable,
106103
cloneJumpMap,
107104
Frame,
108105
JumpMap,
@@ -111,6 +108,9 @@ import {
111108
recurse,
112109
tailRecurse,
113110
} from "./frame";
111+
import {
112+
infixOpMap,
113+
} from "./infix";
114114
import {
115115
prefixOpMap,
116116
} from "./prefix";
@@ -119,9 +119,6 @@ import {
119119
isStatementKind,
120120
kindAndPayloadOfNode,
121121
} from "./reify";
122-
import {
123-
stringify,
124-
} from "./stringify";
125122
import {
126123
ArrayValue,
127124
BoolValue,
@@ -192,8 +189,6 @@ export function initializeEnv(
192189
return env;
193190
}
194191

195-
const comparisonOps = new Set(["<", "<=", ">", ">=", "==", "!="]);
196-
197192
function load(
198193
compUnit: SyntaxNode,
199194
staticEnvs: Map<SyntaxNode, Env>,
@@ -207,14 +202,6 @@ function load(
207202
);
208203
}
209204

210-
function assertNotAssignable(frame: Frame) {
211-
if (frame.mode === Mode.GetCell) {
212-
throw new E607_CannotAssignError(
213-
"Cannot assign to " + frame.node.kind.name
214-
);
215-
}
216-
}
217-
218205
function zip<T, U>(ts: Array<T>, us: Array<U>): Array<[T, U]> {
219206
if (ts.length !== us.length) {
220207
throw new E000_InternalError(
@@ -609,263 +596,14 @@ handlerMap.set(SyntaxKind.PREFIX_OP_EXPR, (frame) => {
609596
});
610597

611598
handlerMap.set(SyntaxKind.INFIX_OP_EXPR, (frame) => {
612-
// let lhs = infixOpExprLhs(node);
613-
// let opName = infixOpExprOpName(node).payload as string;
614-
// let rhs = infixOpExprRhs(node);
615-
// if (opName !== "=") {
616-
// assertNotAssignable();
617-
// }
618-
// if (["+", "-", "*", "//", "%"].includes(opName)) { // [0]
619-
// let left = eval(lhs);
620-
// if (!(left instanceof IntValue)) { // [1]
621-
// throw new E603_TypeError(`Expected Int as lhs of ${opName}`);
622-
// }
623-
// let right = eval(rhs);
624-
// if (!(right instanceof IntValue)) { // [2]
625-
// throw new E603_TypeError(`Expected Int as rhs of ${opName}`);
626-
// }
627-
// if (opName === "+") {
628-
// return new IntValue(left.payload + right.payload);
629-
// }
630-
// else if (opName === "-") {
631-
// return new IntValue(left.payload - right.payload);
632-
// }
633-
// else if (opName === "*") {
634-
// return new IntValue(left.payload * right.payload);
635-
// }
636-
// else if (opName === "//") {
637-
// if (!(right instanceof IntValue)) {
638-
// throw new E603_TypeError("Expected Int as rhs of //");
639-
// }
640-
// if (right.payload === 0n) {
641-
// throw new E601_ZeroDivisionError("Division by 0");
642-
// }
643-
// let negative = left.payload < 0n !== right.payload < 0n;
644-
// let nonZeroMod = left.payload % right.payload !== 0n;
645-
// let diff = negative && nonZeroMod ? 1n : 0n;
646-
// return new IntValue(left.payload / right.payload - diff);
647-
// }
648-
// else if (opName === "%") {
649-
// if (!(right instanceof IntValue)) {
650-
// throw new E603_TypeError("Expected Int as rhs of %");
651-
// }
652-
// if (right.payload === 0n) {
653-
// throw new E601_ZeroDivisionError("Division by 0");
654-
// }
655-
// return new IntValue(left.payload % right.payload);
656-
// }
657-
// else if (comparisonOps.has(opName)) {
658-
// let compareResult = evaluateComparison(left, opName, right);
659-
// return new BoolValue(compareResult);
660-
// }
661-
// }
662-
// else if (opName === "~") {
663-
// let left = eval(lhs);
664-
// let strLeft = stringify(left); // [3]
665-
// let right = eval(rhs);
666-
// let strRight = stringify(right); // [4]
667-
// return new StrValue(strLeft.payload + strRight.payload);
668-
// }
669-
// else if (comparisonOps.has(opName)) {
670-
// let left = eval(lhs);
671-
// let right = eval(rhs); // [7]
672-
// // [8]
673-
// let compareResult = evaluateComparison(left, opName, right);
674-
// return new BoolValue(compareResult);
675-
// }
676-
// else if (opName === "&&") {
677-
// let left = eval(lhs);
678-
// return boolify(left) // [5]
679-
// ? eval(rhs)
680-
// : left;
681-
// }
682-
// }
683-
// else if (opName === "||") {
684-
// let left = eval(lhs);
685-
// return boolify(left) // [6]
686-
// ? left
687-
// : eval(rhs);
688-
// }
689-
// else if (opName === "=") {
690-
// let cell = evalCell(lhs);
691-
// let value = eval(rhs); // [9]
692-
// assign(cell, value); // [10]
693-
// if (mode === Mode.GetValue) {
694-
// return value;
695-
// }
696-
// else if (mode === Mode.GetCell) {
697-
// return cell;
698-
// }
699-
// }
700-
// else {
701-
// throw new E000_InternalError(`Unknown infix op ${opName}`);
702-
// }
703599
let opName = infixOpExprOpName(frame.node).payload as string;
704-
if (opName !== "=") {
705-
assertNotAssignable(frame);
706-
}
707-
switch (frame.state) {
708-
case 0: {
709-
if (["+", "-", "*", "//", "%"].includes(opName)) {
710-
let lhs = infixOpExprLhs(frame.node);
711-
return recurse(frame, 1, { node: lhs });
712-
}
713-
else if (opName === "~") {
714-
let lhs = infixOpExprLhs(frame.node);
715-
return recurse(frame, 3, { node: lhs });
716-
}
717-
else if (comparisonOps.has(opName)) {
718-
let lhs = infixOpExprLhs(frame.node);
719-
return recurse(frame, 7, { node: lhs });
720-
}
721-
else if (opName === "&&") {
722-
let lhs = infixOpExprLhs(frame.node);
723-
return recurse(frame, 5, { node: lhs });
724-
}
725-
else if (opName === "||") {
726-
let lhs = infixOpExprLhs(frame.node);
727-
return recurse(frame, 6, { node: lhs });
728-
}
729-
else if (opName === "=") {
730-
let lhs = infixOpExprLhs(frame.node);
731-
return recurse(frame, 9, { node: lhs, mode: Mode.GetCell });
732-
}
733-
else {
734-
throw new E000_InternalError(`Unknown infix op ${opName}`);
735-
}
736-
}
737-
case 1: {
738-
let left = frame.value;
739-
if (!(left instanceof IntValue)) {
740-
throw new E603_TypeError(`Expected Int as lhs of ${opName}`);
741-
}
742-
frame.v1 = left;
743-
let rhs = infixOpExprRhs(frame.node);
744-
return recurse(frame, 2, { node: rhs });
745-
}
746-
case 2: {
747-
let left = frame.v1 as IntValue;
748-
let right = frame.value;
749-
if (!(right instanceof IntValue)) {
750-
throw new E603_TypeError(`Expected Int as rhs of ${opName}`);
751-
}
752-
if (opName === "+") {
753-
return frame.mode === Mode.Ignore
754-
? new NoneValue()
755-
: new IntValue(left.payload + right.payload);
756-
}
757-
else if (opName === "-") {
758-
return frame.mode === Mode.Ignore
759-
? new NoneValue()
760-
: new IntValue(left.payload - right.payload);
761-
}
762-
else if (opName === "*") {
763-
return frame.mode === Mode.Ignore
764-
? new NoneValue()
765-
: new IntValue(left.payload * right.payload);
766-
}
767-
else if (opName === "//") {
768-
if (!(right instanceof IntValue)) {
769-
throw new E603_TypeError("Expected Int as rhs of //");
770-
}
771-
if (right.payload === 0n) {
772-
throw new E601_ZeroDivisionError("Division by 0");
773-
}
774-
let negative = left.payload < 0n !== right.payload < 0n;
775-
let nonZeroMod = left.payload % right.payload !== 0n;
776-
let diff = negative && nonZeroMod ? 1n : 0n;
777-
return frame.mode === Mode.Ignore
778-
? new NoneValue()
779-
: new IntValue(left.payload / right.payload - diff);
780-
}
781-
else if (opName === "%") {
782-
if (!(right instanceof IntValue)) {
783-
throw new E603_TypeError("Expected Int as rhs of %");
784-
}
785-
if (right.payload === 0n) {
786-
throw new E601_ZeroDivisionError("Division by 0");
787-
}
788-
return frame.mode === Mode.Ignore
789-
? new NoneValue()
790-
: new IntValue(left.payload % right.payload);
791-
}
792-
}
793-
case 3: {
794-
let left = frame.value;
795-
let strLeft = stringify(left);
796-
frame.v1 = strLeft;
797-
let rhs = infixOpExprRhs(frame.node);
798-
return recurse(frame, 4, { node: rhs });
799-
}
800-
case 4: {
801-
let strLeft = frame.v1 as StrValue;
802-
let right = frame.value;
803-
let strRight = stringify(right);
804-
return frame.mode === Mode.Ignore
805-
? new NoneValue()
806-
: new StrValue(strLeft.payload + strRight.payload);
807-
}
808-
case 5: {
809-
let left = frame.value;
810-
let rhs = infixOpExprRhs(frame.node);
811-
if (boolify(left)) {
812-
return tailRecurse(frame, { node: rhs });
813-
}
814-
else {
815-
return frame.mode === Mode.Ignore
816-
? new NoneValue()
817-
: left;
818-
}
819-
}
820-
case 6: {
821-
let left = frame.value;
822-
let rhs = infixOpExprRhs(frame.node);
823-
if (boolify(left)) {
824-
return frame.mode === Mode.Ignore
825-
? new NoneValue()
826-
: left;
827-
}
828-
else {
829-
return tailRecurse(frame, { node: rhs });
830-
}
831-
}
832-
case 7: {
833-
let left = frame.value;
834-
frame.v1 = left;
835-
let rhs = infixOpExprRhs(frame.node);
836-
return recurse(frame, 8, { node: rhs });
837-
}
838-
case 8: {
839-
let left = frame.v1;
840-
let right = frame.value;
841-
let compareResult = evaluateComparison(left, opName, right);
842-
return new BoolValue(compareResult);
843-
}
844-
case 9: {
845-
let rhs = infixOpExprRhs(frame.node);
846-
return recurse(frame, 10, { node: rhs });
847-
}
848-
case 10: {
849-
let cell = frame.cell!;
850-
let value = frame.value;
851-
assign(cell, value);
852-
if (frame.mode === Mode.GetValue) {
853-
return value;
854-
}
855-
else if (frame.mode === Mode.GetCell) {
856-
return cell;
857-
}
858-
else if (frame.mode === Mode.Ignore) {
859-
return new NoneValue();
860-
}
861-
else {
862-
throw new E000_InternalError(
863-
`Unknown mode in '=' (${frame.mode.name})`
864-
);
865-
}
866-
}
600+
let handler = infixOpMap.get(opName);
601+
if (handler === undefined) {
602+
throw new E000_InternalError(
603+
`Missing handler for infix op '${opName}'`
604+
);
867605
}
868-
throw new E000_InternalError("Unreachable state");
606+
return handler(frame);
869607
});
870608

871609
handlerMap.set(SyntaxKind.CHAINED_OP_EXPR, (frame) => {

src/runtime/frame.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from "./env";
1212
import {
1313
E000_InternalError,
14+
E607_CannotAssignError,
1415
} from "./error";
1516
import {
1617
NoneValue,
@@ -144,3 +145,11 @@ export function tailRecurse(
144145
);
145146
}
146147

148+
export function assertNotAssignable(frame: Frame) {
149+
if (frame.mode === Mode.GetCell) {
150+
throw new E607_CannotAssignError(
151+
"Cannot assign to " + frame.node.kind.name
152+
);
153+
}
154+
}
155+

0 commit comments

Comments
 (0)