/**
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
*
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
*
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
*
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
*
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
import {
set, deref, is_structure, make_check,
check_integer, MAX_ARITY, check_nil,
exec_build, exec_unify, fs
} from "../../nova/core.mjs";
function PiWam() {
this.code = undefined;
this.state = undefined;
}
function run(pi) {
let pc = 0;
let accu = 0;
while (pc < pi.code.length) {
let instr = pi.code[pc++];
let value = run_get(pi, instr);
accu = run_fun(instr, accu, value);
run_set(pi, instr, accu);
pc += run_jump(instr, accu);
}
}
function run_get(pi, instr) {
let act = instr >> 20;
let obj = ((instr >> 10) & 0x03FF) - 512;
switch ((act >> 4) & 0x0F) {
case 0: /* get */
return pi.state[obj];
case 1: /* cst */
return obj;
case 2: /* set */
return 0;
case 4: /* out */
return 0;
case 5: /* in */
fs.writeSync(process.stdout.fd, ": ");
return Number(BigInt.asIntN(32, readBig()));
default:
throw new Error("illegal mode");
}
}
function run_fun(instr, accu, value) {
let act = instr >> 20;
switch (act >> 8) {
case 0: /* val */
return value;
case 1: /* acc */
return accu;
case 2: /* add */
return (value + accu) | 0;
case 3: /* sub */
return (value - accu) | 0;
case 4: /* mul */
return Math.imul(value, accu);
case 8: /* nil */
/* t.b.d. */
return 0;
case 9: /* cons */
/* t.b.d. */
return 0;
case 10: /* car */
/* t.b.d. */
return 0;
case 11: /* cdr */
/* t.b.d. */
return 0;
default:
throw new Error("illegal fun");
}
}
function run_set(pi, instr, accu) {
let act = instr >> 20;
let obj = ((instr >> 10) & 0x03FF) - 512;
switch ((act >> 4) & 0x0F) {
case 0: /* get */
return;
case 1: /* cst */
return;
case 2: /* set */
pi.state[obj] = accu;
return;
case 4: /* out */
fs.writeSync(process.stdout.fd, accu.toString()+"\n");
return;
case 5: /* in */
return;
default:
throw new Error("illegal mode");
}
}
function run_jump(instr, accu) {
let act = instr >> 20;
let rel = (instr & 0x03FF) - 512;
switch (act & 0x0F) {
case 0: /* eq */
return (accu === 0 ? rel : 0);
case 1: /* nq */
return (accu !== 0 ? rel : 0);
case 2: /* ls */
return (accu < 0 ? rel : 0);
case 3: /* gr */
return (accu > 0 ? rel : 0);
case 4: /* lq */
return (accu <= 0 ? rel : 0);
case 5: /* gq */
return (accu >= 0 ? rel : 0);
case 8: /* unit */
/* t.b.d. */
return 0;
case 9: /* pair */
/* t.b.d. */
return 0;
case 15: /* true */
return rel;
default:
throw new Error("illegal cond");
}
}
/******************************************************************/
/* π-WAM Input */
/******************************************************************/
function readBig() {
let res = Buffer.alloc(1024);
let len = fs.readSync(0, res, 0, 1024);
return BigInt(res.toString('utf8', 0, len));
}
/******************************************************************/
/* π-WAM Interface */
/******************************************************************/
/**
* test_ir_piwam_new(C, S, P): internal only
* The predicate succeeds in P with a CPU backed π-WAM for
* the code C and the state S.
*/
function test_ir_piwam_new(args) {
let pi = new PiWam();
let alpha = exec_build(args[0]);
pi.code = list_ints(alpha);
let beta = exec_build(args[1]);
pi.state = list_ints(beta);
return exec_unify(args[2], pi);
}
function list_ints(obj) {
let peek = obj;
let i = 0;
while (is_structure(peek) &&
"." === peek.functor &&
peek.args.length === 2 &&
i < MAX_ARITY) {
i++;
peek = deref(peek.args[1]);
}
check_nil(peek);
let args = new Array(i);
peek = obj;
i = 0;
while (is_structure(peek) &&
"." === peek.functor &&
peek.args.length === 2) {
let val = deref(peek.args[0]);
check_integer(val);
if (typeof val === 'number') {
args[i++] = val | 0;
} else {
args[i++] = Number(BigInt.asIntN(32, val));
}
peek = deref(peek.args[1]);
}
return args;
}
/**
* test_ir_piwam_run(P): internal only
* The predicate fails. As a side effect it will run the
* π-WAM P in the current thread. The predicate terminates
* when the π-WAM P terminates.
*/
function test_ir_piwam_run(args) {
let alpha = exec_build(args[0]);
run(alpha);
return false;
}
/******************************************************************/
/* π-WAM Lib Init */
/******************************************************************/
export function main() {
set("ir_piwam_new", 3, make_check(test_ir_piwam_new));
set("ir_piwam_run", 1, make_check(test_ir_piwam_run));
}