Last active 1745081612

spell_zine.js Raw Playground
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
14var C = (t,k,n) => t[k] = (k in t ? t[k] : 0) + n;
15var spl = (d) => (i) => i.split(d).filter(c => !!c)
16
17// Lay the circle, trace the lines
18var R = [], I = [] // Recipes (rules) and Inventory (current facts)
19
20// Eval
21var 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
45var 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
57var H = (...n) => n.reduce((h, f) => h && I[f], !0 )
58
59// Register (W stands for Write)
60var 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// }
88