implement more operators and coerce types (#804)

* implement more operators and coerce types

* add remaining operators
This commit is contained in:
jberg 2019-07-12 09:55:49 -07:00 committed by Jordan Eldredge
parent bf5c3e9078
commit 4e880ab130
3 changed files with 170 additions and 9 deletions

View file

@ -13,10 +13,10 @@ const COMMANDS = {
},
"8": { name: "eq", short: "==", in: "2", out: "1" },
"9": { name: "heq", short: "!=", in: "2", out: "1" },
"10": { name: "le", short: "<", in: "2", out: "1" },
"11": { name: "leq", short: "<=", in: "2", out: "1" },
"12": { name: "gt", short: ">", in: "2", out: "1" },
"13": { name: "gtq", short: ">=", in: "2", out: "1" },
"10": { name: "gt", short: ">", in: "2", out: "1" },
"11": { name: "gtq", short: ">=", in: "2", out: "1" },
"12": { name: "le", short: "<", in: "2", out: "1" },
"13": { name: "leq", short: "<=", in: "2", out: "1" },
"16": { name: "jumpIf", short: "if", arg: "line", in: "1", out: "0" },
"17": { name: "jumpIfNot", arg: "line", in: "1", out: "0" },

View file

@ -94,6 +94,31 @@ describe("can use basic operators", () => {
"4 >> 1 = 2",
"2.5 << 1 = 4 (implict casting)",
"4.5 >> 1 = 2 (implict casting)",
"1 != 2",
"1 < 2",
"2 > 1",
"[int] 4 = [float] 4.4 (autocasting types)",
"[int] 4 <= [float] 4.4 (autocasting types)",
"[int] 4 >= [float] 4.4 (autocasting types)",
"! [int] 4 < [float] 4.4 (autocasting types)",
"! [int] 4 > [float] 4.4 (autocasting types)",
"1++ = 1",
"1++ (after incremeent) = 2",
"2-- = 2",
"2-- (after decrement) = 1",
"++1 = 2",
"!f",
"!0",
"!1 == 0",
"1 == 1",
"0 == 0",
"1 && 1",
"!(1 && 0)",
"!(0 && 0)",
"1 || 1",
"1 || 0",
"0 || 1",
"!(0 || 0)",
].map(successOutputFromMessage)
);
});

View file

@ -1,5 +1,21 @@
const Variable = require("./variable");
function coerceTypes (var1, var2, val1, val2) {
if (var1.type === 'INT') {
if (var2.type === 'FLOAT' || var2.type === 'DOUBLE') {
return [val1, Math.floor(val2)];
}
}
if (var2.type === 'INT') {
if (var1.type === 'FLOAT' || var1.type === 'DOUBLE') {
return [Math.floor(val1), val2];
}
}
return [val1, val2];
}
async function interpret(start, program, { logger = null }) {
const { commands, methods, variables, classes, offsetToCommand } = program;
@ -28,11 +44,62 @@ async function interpret(start, program, { logger = null }) {
const b = stack.pop();
// I'm suspicious about this. Should we really be storing both values
// and variables on the stack.
const aValue = a instanceof Variable ? a.getValue() : a;
const bValue = b instanceof Variable ? b.getValue() : b;
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(aValue === bValue);
break;
}
// !=
case 9: {
const a = stack.pop();
const b = stack.pop();
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(aValue !== bValue);
break;
}
// >
case 10: {
const a = stack.pop();
const b = stack.pop();
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(bValue > aValue);
break;
}
// >=
case 11: {
const a = stack.pop();
const b = stack.pop();
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(bValue >= aValue);
break;
}
// <
case 12: {
const a = stack.pop();
const b = stack.pop();
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(bValue < aValue);
break;
}
// <=
case 13: {
const a = stack.pop();
const b = stack.pop();
let aValue = a instanceof Variable ? a.getValue() : a;
let bValue = b instanceof Variable ? b.getValue() : b;
[aValue, bValue] = coerceTypes(a, b, aValue, bValue);
stack.push(bValue <= aValue);
break;
}
// jumpIf
case 16: {
const value = stack.pop();
@ -82,8 +149,41 @@ async function interpret(start, program, { logger = null }) {
case 48: {
const a = stack.pop();
const b = stack.pop();
b.setValue(a);
stack.push(a);
const aValue = a instanceof Variable ? a.getValue() : a;
b.setValue(aValue);
stack.push(aValue);
break;
}
// postinc
case 56: {
const a = stack.pop();
const aValue = a.getValue();
a.setValue(aValue + 1);
stack.push(aValue);
break;
}
// postdec
case 57: {
const a = stack.pop();
const aValue = a.getValue();
a.setValue(aValue - 1);
stack.push(aValue);
break;
}
// preinc
case 58: {
const a = stack.pop();
const aValue = a.getValue() + 1;
a.setValue(aValue);
stack.push(aValue);
break;
}
// predec
case 59: {
const a = stack.pop();
const aValue = a.getValue() - 1;
a.setValue(aValue);
stack.push(aValue);
break;
}
// + (add)
@ -150,10 +250,46 @@ async function interpret(start, program, { logger = null }) {
stack.push(bValue | aValue);
break;
}
// ! (not)
case 74: {
const a = stack.pop();
const aValue = a instanceof Variable ? a.getValue() : a;
stack.push(aValue ? 0 : 1);
break;
}
// - (negative)
case 76: {
const a = stack.pop();
stack.push(-a.getValue());
const aValue = a instanceof Variable ? a.getValue() : a;
stack.push(-aValue);
break;
}
// logAnd (&&)
case 80: {
const a = stack.pop();
const aValue = a instanceof Variable ? a.getValue() : a;
if (!aValue) {
stack.push(false);
break;
}
const b = stack.pop();
const bValue = b instanceof Variable ? b.getValue() : b;
stack.push(!!bValue);
break;
}
// logOr ||
case 81: {
const a = stack.pop();
const aValue = a instanceof Variable ? a.getValue() : a;
if (aValue) {
stack.push(true);
break;
}
const b = stack.pop();
const bValue = b instanceof Variable ? b.getValue() : b;
stack.push(!!bValue);
break;
}
// <<