mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-24 02:36:00 +00:00
implement more operators and coerce types (#804)
* implement more operators and coerce types * add remaining operators
This commit is contained in:
parent
bf5c3e9078
commit
4e880ab130
3 changed files with 170 additions and 9 deletions
|
|
@ -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" },
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
// <<
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue