// Build: // npx google-closure-compiler -O SIMPLE minmoire.js > minmoire.min.js && du -b minmoire.min.js // Changes from base grimoire: // - API names // - Rules are two-length arrays rather than {needs, makes} objects // - Some compressed logic. Eg. removed do/while for executing facts, which may change behavior of edge cases // - parsing based on .split() rather than regex matches // - Assumes various ES6+ syntax // - various heresies like var (instead of const), omitting { } from if statements, etc // Grab the salt // note: "Tally" renamed to C, standing for Count var C = (t,k,n) => t[k] = (k in t ? t[k] : 0) + n; var spl = (d) => (i) => i.split(d).filter(c => !!c) // Lay the circle, trace the lines var R = [], I = [] // Recipes (rules) and Inventory (current facts) // Eval var E = (i='') => { P(i); // following code was formerly the run() function for (var r of R) { // recipe for (var n in r[0]) { if ((I[n] || 0) < r[0][n]) break; } // deduct needs for (var n in r[0]) C(I, n, -r[0][n]); // add (or execute) makes for (var m in r[1]) { var cq = r[1][m] // consequence try { cq(I); } catch { // Consequence is assumed to be a number C(I, m, cq); } } } } // Parse into inventory var P = (i) => { // Mode characters; order matters for : and ; // (state variable `m` is initialized here) var ms = [ ':', '>', m = ';']; for (let [t, c] of spl(/[^\S]/)(i).map(spl('^'))) { // token, count if (t == ':') W(); if (ms.includes(t)) m = t; else C((m == ';') ? I : R.at(-1)[ms.indexOf(m)], t, parseInt(c) || 1); } } // Has var H = (...n) => n.reduce((h, f) => h && I[f], !0 ) // Register (W stands for Write) var W = (N={}, M={}) => R.push([ N, M ]) // Basic test // const program = ` // : a > b ; // : b^100 > overflow_b ; // : > a b^99 c // `; // E(program); // console.assert( // H("overflow_b") // && !H("a") // && !H("b") // && H("c") // ) // W({overflow_b:1}, {overflow_b:function() {console.log('Too much B!')}}) // E() // Original readable API // const grimoire = { // recipes: R, // inventory: I, // eval: E, // parse: P, // // note: run() was folded into eval() // has: H, // register: W // }