tcl-js
Version:
tcl-js is a tcl intepreter written completely in Typescript. It is meant to replicate the tcl-sh interpreter as closely as possible.
74 lines (72 loc) • 2.15 kB
JavaScript
import { INUMBER, IOP1, IOP2, IOP3, IVAR, IFUNCALL, IEXPR, IMEMBER } from './instruction';
export default function evaluate(tokens, expr, values) {
var nstack = [];
var n1, n2, n3;
var f;
for (var i = 0; i < tokens.length; i++) {
var item = tokens[i];
var type = item.type;
if (type === INUMBER) {
nstack.push(item.value);
} else if (type === IOP2) {
n2 = nstack.pop();
n1 = nstack.pop();
if (item.value === '&&') {
nstack.push(n1 ? !!evaluate(n2, expr, values) : false);
} else if (item.value === '||') {
nstack.push(n1 ? true : !!evaluate(n2, expr, values));
} else {
f = expr.binaryOps[item.value];
nstack.push(f(n1, n2));
}
} else if (type === IOP3) {
n3 = nstack.pop();
n2 = nstack.pop();
n1 = nstack.pop();
if (item.value === '?') {
nstack.push(evaluate(n1 ? n2 : n3, expr, values));
} else {
f = expr.ternaryOps[item.value];
nstack.push(f(n1, n2, n3));
}
} else if (type === IVAR) {
if (item.value in expr.functions) {
nstack.push(expr.functions[item.value]);
} else {
var v = values[item.value];
if (v !== undefined) {
nstack.push(v);
} else {
throw new Error('undefined variable: ' + item.value);
}
}
} else if (type === IOP1) {
n1 = nstack.pop();
f = expr.unaryOps[item.value];
nstack.push(f(n1));
} else if (type === IFUNCALL) {
var argCount = item.value;
var args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
f = nstack.pop();
if (f.apply && f.call) {
nstack.push(f.apply(undefined, args));
} else {
throw new Error(f + ' is not a function');
}
} else if (type === IEXPR) {
nstack.push(item.value);
} else if (type === IMEMBER) {
n1 = nstack.pop();
nstack.push(n1[item.value]);
} else {
throw new Error('invalid Expression');
}
}
if (nstack.length > 1) {
throw new Error('invalid Expression (parity)');
}
return nstack[0];
}