diff --git a/experiments/modern/src/maki-interpreter/constants.js b/experiments/modern/src/maki-interpreter/constants.js index 5e3ac4dd..109f9503 100644 --- a/experiments/modern/src/maki-interpreter/constants.js +++ b/experiments/modern/src/maki-interpreter/constants.js @@ -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" }, diff --git a/experiments/modern/src/maki-interpreter/interpreter.test.js b/experiments/modern/src/maki-interpreter/interpreter.test.js index 69171698..5c4f64ed 100644 --- a/experiments/modern/src/maki-interpreter/interpreter.test.js +++ b/experiments/modern/src/maki-interpreter/interpreter.test.js @@ -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) ); }); diff --git a/experiments/modern/src/maki-interpreter/virtualMachine.js b/experiments/modern/src/maki-interpreter/virtualMachine.js index 74359bca..8fa51627 100644 --- a/experiments/modern/src/maki-interpreter/virtualMachine.js +++ b/experiments/modern/src/maki-interpreter/virtualMachine.js @@ -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; } // <<