Last active 1745081612

yumaikas's Avatar yumaikas revised this gist 1745081612. Go to revision

1 file changed, 87 insertions

spell_zine.js(file created)

@@ -0,0 +1,87 @@
1 + // Build:
2 + // npx google-closure-compiler -O SIMPLE minmoire.js > minmoire.min.js && du -b minmoire.min.js
3 +
4 + // Changes from base grimoire:
5 + // - API names
6 + // - Rules are two-length arrays rather than {needs, makes} objects
7 + // - Some compressed logic. Eg. removed do/while for executing facts, which may change behavior of edge cases
8 + // - parsing based on .split() rather than regex matches
9 + // - Assumes various ES6+ syntax
10 + // - various heresies like var (instead of const), omitting { } from if statements, etc
11 +
12 + // Grab the salt
13 + // note: "Tally" renamed to C, standing for Count
14 + var C = (t,k,n) => t[k] = (k in t ? t[k] : 0) + n;
15 + var spl = (d) => (i) => i.split(d).filter(c => !!c)
16 +
17 + // Lay the circle, trace the lines
18 + var R = [], I = [] // Recipes (rules) and Inventory (current facts)
19 +
20 + // Eval
21 + var E = (i='') => {
22 + P(i);
23 + // following code was formerly the run() function
24 + for (var r of R) { // recipe
25 + for (var n in r[0]) {
26 + if ((I[n] || 0) < r[0][n]) break;
27 + }
28 + // deduct needs
29 + for (var n in r[0]) C(I, n, -r[0][n]);
30 + // add (or execute) makes
31 + for (var m in r[1]) {
32 + var cq = r[1][m] // consequence
33 + try {
34 + cq(I);
35 + }
36 + catch {
37 + // Consequence is assumed to be a number
38 + C(I, m, cq);
39 + }
40 + }
41 + }
42 + }
43 +
44 + // Parse into inventory
45 + var P = (i) => {
46 + // Mode characters; order matters for : and ;
47 + // (state variable `m` is initialized here)
48 + var ms = [ ':', '>', m = ';'];
49 + for (let [t, c] of spl(/[^\S]/)(i).map(spl('^'))) { // token, count
50 + if (t == ':') W();
51 + if (ms.includes(t)) m = t;
52 + else C((m == ';') ? I : R.at(-1)[ms.indexOf(m)], t, parseInt(c) || 1);
53 + }
54 + }
55 +
56 + // Has
57 + var H = (...n) => n.reduce((h, f) => h && I[f], !0 )
58 +
59 + // Register (W stands for Write)
60 + var W = (N={}, M={}) => R.push([ N, M ])
61 +
62 + // Basic test
63 + // const program = `
64 + // : a > b ;
65 + // : b^100 > overflow_b ;
66 + // : > a b^99 c
67 + // `;
68 + // E(program);
69 + // console.assert(
70 + // H("overflow_b")
71 + // && !H("a")
72 + // && !H("b")
73 + // && H("c")
74 + // )
75 + // W({overflow_b:1}, {overflow_b:function() {console.log('Too much B!')}})
76 + // E()
77 +
78 + // Original readable API
79 + // const grimoire = {
80 + // recipes: R,
81 + // inventory: I,
82 + // eval: E,
83 + // parse: P,
84 + // // note: run() was folded into eval()
85 + // has: H,
86 + // register: W
87 + // }
Newer Older