@dallaylaen/ski-interpreter 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/bin/ski.js +7 -10
- package/lib/ski-interpreter.cjs.js +74 -60
- package/lib/ski-interpreter.cjs.js.map +3 -3
- package/lib/ski-interpreter.min.js +5 -5
- package/lib/ski-interpreter.min.js.map +4 -4
- package/lib/ski-interpreter.mjs +74 -60
- package/lib/ski-interpreter.mjs.map +3 -3
- package/lib/ski-quest.min.js +5 -5
- package/lib/ski-quest.min.js.map +4 -4
- package/lib/types/expr.d.ts +33 -6
- package/lib/types/extras.d.ts +4 -10
- package/lib/types/index.d.ts +2 -5
- package/lib/types/parser.d.ts +11 -13
- package/package.json +1 -1
package/lib/ski-quest.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
1
|
+
"use strict";(()=>{var G=Object.defineProperty;var Ne=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var $e=Object.prototype.hasOwnProperty;var O=(r,e)=>()=>(r&&(e=r(r=0)),e);var V=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),Me=(r,e)=>{for(var t in e)G(r,t,{get:e[t],enumerable:!0})},Qe=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Pe(e))!$e.call(r,s)&&s!==t&&G(r,s,{get:()=>e[s],enumerable:!(n=Ne(e,s))||n.enumerable});return r};var Ue=r=>Qe(G({},"__esModule",{value:!0}),r);function K(r,e){if(!e)return r;let t=new Set([...r]),n="=",s={"=":i=>{t=new Set([i]),n="+"},"+":i=>{t.add(i)},"-":i=>{t.delete(i)}};for(let i of Ke.split(e))s[i]?n=i:s[n](i);return t}function k(r){return r instanceof U?[r.value??void 0,r.decoration]:[r??void 0,void 0]}function q(r){let e=t=>new U(t,e);return e.label=r,e.toString=()=>"TraverseControl::"+r,e}var L,Ke,U,J=O(()=>{"use strict";L=class{constructor(...e){let t="$|(\\s+)|"+e.map(n=>"(?:"+n+")").sort((n,s)=>s.length-n.length).join("|");this.rex=new RegExp(t,"gys")}split(e){this.rex.lastIndex=0;let t=[...e.matchAll(this.rex)],s=t.pop()?.index??0;if(s!==e.length)throw new Error("Unknown tokens at pos "+s+"/"+e.length+" starting with "+e.substring(s));return t.filter(i=>i[1]===void 0).map(i=>i[0])}},Ke=new L("[-=+]","[A-Z]","\\b[a-z_][a-z_0-9]*\\b");U=class{constructor(e,t){this.value=e,this.decoration=t}}});function Y(r){return r<=1?e=>t=>e.apply(t):e=>t=>Y(r-1)(e.apply(t))}function I(r,e,t={}){y[r]=new z(r,e,t)}function De(r){for(;r instanceof T;)r=r.fun;return r instanceof m}function ge(r,e,t){let n=new Array(r.length).fill(0),s=!0;e.traverse(o=>{if(o instanceof m){let l=r.findIndex(u=>u.name===o.name);if(l>=0){n[l]++;return}}o instanceof T||(s=!1)});let i=new Set,a=new Set;for(let o=0;o<r.length;o++)n[o]===0?i.add(o):n[o]>1&&a.add(o);for(let o=r.length;o-- >0;)e=new E(r[o],e);return{normal:!0,steps:t.steps,expr:e,arity:r.length,...i.size?{skip:i}:{},...a.size?{dup:a}:{},duplicate:!!a.size||t.duplicate||!1,discard:!!i.size||t.discard||!1,proper:s}}function xe(r){return new m("abcdefgh"[r]??"x"+r)}function C(r){if(typeof r!="object"||r===null||Array.isArray(r)||r instanceof v)throw new Error("positional arguments to toposort are deprecated, use { list: ..., env: ... } instead");let e=r.allow?{...r.allow}:null,t={...r.env??{}},n=r.list instanceof v?[r.list]:r.list??[];if(e)for(let o of n)o instanceof w&&(e[o.name]=o);for(let o of n)o instanceof w&&t[o.name]===o&&delete t[o.name];let s=[],i=new Set(Object.values(t)),a=o=>{i.has(o)||(o.fold(void 0,(l,u)=>{if(u instanceof w&&!(e&&e[u.name]!==u)&&!(!e&&u instanceof d&&u.inline)&&u!==o)return a(u),h.prune()}),s.push(o),i.add(o),o instanceof w&&(t[o.name]||=o))};for(let o of n)a(o);return{list:s,env:t}}var F,Be,h,y,v,T,w,He,m,z,E,A,d,be,j=O(()=>{"use strict";J();F={max:1e3,maxArgs:32,maxSize:1e6},Be={"leftmost-outermost":"LO","leftmost-innermost":"LI",LO:"LO",LI:"LI"},h={descend:q("descend"),prune:q("prune"),redo:q("redo"),stop:q("stop")},y={},v=class r{annotate(e={}){if(e.fancy!==void 0&&this instanceof w&&(this.fancyName=e.fancy),e.note!==void 0&&(this.note=e.note),e.arity!==void 0&&(this.arity=e.arity),e.canonize){let t=this.infer(e);t.normal&&(this.arity=this.arity??t.arity,this.note=this.note??t.expr.format({html:!0,lambda:[""," ↦ ",""]}),delete t.steps,this.props=t)}return this}apply(...e){let t=this;for(let n of e)t=new T(t,n);return t}expand(){return this.traverse(e=>{if(e instanceof d)return e.impl.expand()})??this}traverse(e,t){typeof e=="function"&&(t=e,e={});let n=Be[e.order??"LO"];if(n===void 0)throw new Error("Unknown traversal order: "+e.order);let[s]=k(this._traverse_redo({order:n},t));return s??null}_traverse_redo(e,t){let n,s=this,i;do{i=s;let a=e.order==="LI"?s._traverse_descend(e,t)??t(s):t(s)??s._traverse_descend(e,t);[s,n]=k(a)}while(s&&n===h.redo);return!s&&i!==this&&(s=i),n?n(s):s}_traverse_descend(e,t){return null}any(e){return e(this)}fold(e,t){let[n]=k(this._fold(e,t));return n??e}_fold(e,t){return t(e,this)}foldBottomUp(e){let[t,...n]=this.unroll();return e(t,n.map(s=>s.foldBottomUp(e)))}infer(e={}){let t={},n=new Set;return this.traverse(s=>{s instanceof w&&!n.has(s)&&(t[s.name]=!0),s instanceof E&&n.add(s.arg)}),this._infer({max:e.max??F.max,maxArgs:e.maxArgs??F.maxArgs,maxSize:e.maxSize??F.maxSize,skipNames:t},0)}_infer(e,t){let n=[],s=0,i=this;e:for(let a=0;a<e.maxArgs;a++){let o=i.run({max:e.max-s,maxSize:e.maxSize});if(s+=o.steps,!o.final)break;if(De(o.expr)){if(i=o.expr,!i.any(p=>!(p instanceof m||p instanceof T)))return ge(n,i,{steps:s});let u=i.unroll(),f=!1,b=!1,g=[];for(let p=1;p<u.length;p++){let x=u[p]._infer({maxArgs:e.maxArgs-t,max:e.max-s,maxSize:e.maxSize,skipNames:e.skipNames},t+a);if(s+=x.steps??0,!x.expr)break e;x.discard&&(f=!0),x.duplicate&&(b=!0),g.push(x.expr)}return ge(n,u[0].apply(...g),{discard:f,duplicate:b,steps:s})}for(;e.skipNames[xe(t+a).name];)t++;let l=xe(t+a);n.push(l),i=o.expr.apply(l)}return{normal:!1,proper:!1,steps:s}}unroll(){return[this]}*toLambda(e={}){let t=this.traverse(i=>{if(i instanceof m)return i;if(i instanceof T||i instanceof E||i instanceof d)return null;let a=i.infer({max:e.max,maxArgs:e.maxArgs});if(!a.normal)throw new Error("Failed to infer an equivalent lambda term for "+i);return a.expr})??this,n=new Set,s=0;for(;t;){let i=t.traverse({order:"LI"},a=>{if(n.has(a))return null;if(a instanceof T&&a.fun instanceof E){let o=a.infer({max:e.max,maxArgs:e.maxArgs});return s+=o.steps??0,o.normal?h.stop(o.expr):(n.add(a),null)}});yield{expr:t,steps:s},t=i}}*toSKI(e={}){let t=this.traverse(s=>s instanceof m||s instanceof T||s instanceof E||s instanceof d?null:s.infer(e).expr)??this,n=0;for(;t;){let s=t.traverse({order:"LI"},i=>{if(!(i instanceof E)||i.impl instanceof E)return null;if(i.impl===i.arg)return h.stop(y.I);if(!i.impl.any(a=>a===i.arg))return h.stop(y.K.apply(i.impl));if(!(i.impl instanceof T))throw new Error("toSKI: assert failed: lambda body is of unexpected type "+i.impl.constructor.name);return i.impl.arg===i.arg&&!i.impl.fun.any(a=>a===i.arg)?h.stop(i.impl.fun):h.stop(y.S.apply(new E(i.arg,i.impl.fun),new E(i.arg,i.impl.arg)))});yield{expr:t,steps:n,final:!s},n++,t=s}}subst(e,t){return this===e?t:null}invoke(e){return null}step(){return{expr:this,steps:0,changed:!1}}run(e={},...t){e instanceof r&&(t.unshift(e),e={});let n=t?this.apply(...t):this,s=e.steps??0,i=Math.max(e.max??F.max,1)+s,a=!1;for(;s<i;){let o=n.step();if(!o.changed){a=!0;break}if((o.expr.size??1)>(e.maxSize??F.maxSize))break;s+=o.steps,n=o.expr}if(e.throw&&!a)throw new Error("Failed to compute expression in "+i+" steps");return{final:a,steps:s,expr:n}}*walk(e={}){let t=e.max??1/0,n=0,s=this,i=!1;for(;n<t&&(s.size??1)<(e.maxSize??F.maxSize);){let a=s.step();if(a.changed||(i=!0),yield{expr:s,steps:n,final:i},i)break;n+=a.steps,s=a.expr}}equals(e){return!this.diff(e)}diff(e,t=!1){return this===e?null:e instanceof d?e.impl.diff(this,!t):t?"["+e+" != "+this+"]":"["+this+" != "+e+"]"}expect(e,t=""){if(t=t?t+": ":"",!(e instanceof r))throw new Error(t+"Expected a combinator but found "+(e?.constructor?.name??typeof e));let n=this.diff(e);if(!n)return;let s=new Error(t+n);throw s.expected=this.diag(),s.actual=e.diag(),s}toString(){return this.format()}_braced(e){return!1}_unspaced(e){return this._braced(!0)}format(e={}){let t=e.html?{brackets:["(",")"],space:" ",var:["<var>","</var>"],lambda:["","->",""],around:["",""],redex:["",""]}:{brackets:["(",")"],space:" ",var:["",""],lambda:["","->",""],around:["",""],redex:["",""]};return this.formatImpl({terse:e.terse??!0,brackets:e.brackets??t.brackets,space:e.space??t.space,var:e.var??t.var,lambda:e.lambda??t.lambda,around:e.around??t.around,redex:e.redex??t.redex,inventory:e.inventory,html:e.html??!1},0)}diag(e=""){return e+this.constructor.name+": "+this}declare(e={}){let{declaration:t=["","=","; "],...n}=e,s=C({list:[this],env:n.inventory});return s.list.map(i=>i instanceof d?t[0]+i.name+t[1]+i.impl.format({...n,inventory:s.env}):i instanceof m?t[0]+i.name+t[1]:i.format({...n,inventory:s.env})).join(t[2])}toJSON(){return this.declare()}},T=class r extends v{constructor(e,t){super(),this.arg=t,this.fun=e,this.size=(e.size??1)+(t.size??1)}_traverse_descend(e,t){let[n,s]=k(this.fun._traverse_redo(e,t));if(s===h.stop)return h.stop(n?n.apply(this.arg):null);let[i,a]=k(this.arg._traverse_redo(e,t)),o=n||i?(n??this.fun).apply(i??this.arg):null;return a===h.stop?h.stop(o):o}any(e){return e(this)||this.fun.any(e)||this.arg.any(e)}_fold(e,t){let[n=e,s="descend"]=k(t(e,this));if(s===h.prune)return n;if(s===h.stop)return h.stop(n);let[i=n,a="descend"]=k(this.fun._fold(n,t));if(a===h.stop)return h.stop(i);let[o=i,l="descend"]=k(this.arg._fold(i,t));return l===h.stop?h.stop(o):o}subst(e,t){let n=this.fun.subst(e,t),s=this.arg.subst(e,t);return n||s?(n??this.fun).apply(s??this.arg):null}step(){if(!this.final){let e=this.fun.invoke(this.arg);if(e instanceof v)return{expr:e,steps:1,changed:!0};typeof e=="function"&&(this.invoke=e);let t=this.fun.step();if(t.changed)return{expr:t.expr.apply(this.arg),steps:t.steps,changed:!0};let n=this.arg.step();if(n.changed)return{expr:this.fun.apply(n.expr),steps:n.steps,changed:!0};this.final=!0}return{expr:this,steps:0,changed:!1}}invoke(e){let t=this.fun.invoke(this.arg);return t instanceof v?t.apply(e):typeof t=="function"?(this.invoke=t,t(e)):(this.invoke=n=>null,null)}unroll(){return[...this.fun.unroll(),this.arg]}diff(e,t=!1){if(!(e instanceof r))return super.diff(e,t);let n=this.fun.diff(e.fun,t);if(n)return n+"(...)";let s=this.arg.diff(e.arg,t);return s?this.fun+"("+s+")":null}_braced(e){return!e}formatImpl(e,t){let n=this.fun.formatImpl(e,t+1),s=this.arg.formatImpl(e,0),i=t?["",""]:e.around;return e.terse&&!this.arg._braced(!1)?i[0]+n+(this.fun._unspaced(this.arg)?"":e.space)+s+i[1]:i[0]+n+e.brackets[0]+s+e.brackets[1]+i[1]}diag(e=""){return e+`App:
|
|
2
2
|
`+this.unroll().map(t=>t.diag(e+" ")).join(`
|
|
3
|
-
`)}_unspaced(e){return this.arg._braced(!1)?!0:this.arg._unspaced(e)}},
|
|
4
|
-
`+this.impl.diag(e+" ")}_braced(e){return!0}},A=class r extends
|
|
5
|
-
`+this.impl.diag(e)}};C("I",r=>r);C("K",r=>e=>r);C("S",r=>e=>t=>r.apply(t,e.apply(t)));C("B",r=>e=>t=>r.apply(e.apply(t)));C("C",r=>e=>t=>r.apply(t).apply(e));C("W",r=>e=>r.apply(e).apply(e));C("+",r=>r instanceof A?new A(r.n+1):e=>t=>e.apply(r.apply(e,t)),{note:"Increase a Church numeral argument by 1, otherwise n => f => x => f(n f x)"});we={Expr:w,App:T,Named:v,FreeVar:d,Native:_,Lambda:E,Church:A,Alias:m}});function O(r,e){if(r instanceof w&&(r=[r]),e)r||(r=Object.keys(e).sort().map(i=>e[i]));else{if(!r)return{list:[],env:{}};e={};for(let i of r)if(i instanceof v){if(e[i.name])throw new Error("duplicate name "+i);e[i.name]=i}}let t=[],n=new Set,s=i=>{n.has(i)||(i.fold(!1,(o,a)=>{if(a!==i&&a instanceof v&&e[a.name]===a)return s(a),u.prune(!1)}),t.push(i),n.add(i))};for(let i of r)s(i);return{list:t,env:e}}var B=I(()=>{"use strict";z()});function ve(r){return r.postParse?r.postParse():r}function ee(r,e){for(;e instanceof m&&e.name===r;)e=e.impl;return e instanceof v&&e.name===r?e:new m(r,e,{canonize:!0})}var R,te,We,V,ne=I(()=>{"use strict";Y();z();B();R=class extends w{apply(...e){return e.length>0?e.shift().apply(...e):this}postParse(){throw new Error("Attempt to use empty expression () as a term")}formatImpl(e,t){return"()"}},te=class r extends R{constructor(e,t={}){if(super(),this.impl=new R,e instanceof d)this.terms=[e];else if(e instanceof r){if(!(e.impl instanceof d))throw new Error("Expected FreeVar->...->FreeVar->Expr");this.terms=[...e.terms,e.impl]}else throw new Error("Expected FreeVar or PartialLambda")}apply(e,...t){if(e===null||t.length!==0)throw new Error("bad syntax in partial lambda expr");return this.impl=this.impl.apply(e),this}postParse(){let e=this.impl;for(let t=this.terms.length;t-- >0;)e=new E(this.terms[t],e);return e}};We=new q("[()]","[A-Z]","[a-z_][a-z_0-9]*","\\b[0-9]+\\b","->","\\+"),V=class{constructor(e={}){if(this.annotate=!!e.annotate,this.addContext=!!e.addContext,this.known={...y},this.hasNumbers=!0,this.hasLambdas=!0,this.allow=new Set(Object.keys(this.known)),Array.isArray(e.terms))this.bulkAdd(e.terms);else if(e.terms)for(let t in e.terms)(typeof e.terms[t]!="string"||!e.terms[t].match(/^Native:/))&&this.add(t,e.terms[t]);this.hasNumbers=e.numbers??!0,this.hasLambdas=e.lambdas??!0,e.allow&&this.restrict(e.allow)}add(e,t,n){let s=this._named(e,t),i=typeof n=="string"?{note:n,canonize:!1}:n??{};s._setup({canonize:this.annotate,...i});let o=this.known[s.name];return o instanceof m&&o.makeInline(),this.known[s.name]=s,this.allow.add(s.name),this}_named(e,t){if(e instanceof v)return ee(e.name,e);if(typeof e!="string")throw new Error("add(): term must be an Alias or a string");if(t===void 0)throw new Error("add(): impl must be provided when term is a string");if(typeof t=="string")return ee(e,this.parse(t));if(t instanceof w)return ee(e,t);if(typeof t=="function")return new _(e,t);throw new Error("add(): impl must be an Expr, a string, or a function with a signature Expr => ... => Expr")}maybeAdd(e,t){return this.known[e]?this.allow.add(e):this.add(e,t),this}bulkAdd(e){for(let t of e){let n=t.match(/^([A-Z]|[a-z][a-z_0-9]*)\s*=\s*(.*)$/s);if(!n)throw new Error("bulkAdd: invalid declaration: "+t);n[2]===""?this.remove(n[1]):this.add(n[1],this.parse(n[2]))}return this}restrict(e){return this.allow=K(this.allow,e),this}showRestrict(e="+"){let t=[],n=!0;for(let s of[...K(this.allow,e)].sort()){let i=!!s.match(/^[A-Z]$/);t.length&&!(n&&i)&&t.push(" "),t.push(s),n=i}return t.join("")}remove(e){let t=this.known[e];return t instanceof m&&t.makeInline(),delete this.known[e],this.allow.delete(e),this}getTerms(){let e={};for(let t of Object.keys(this.known))this.allow.has(t)&&(e[t]=this.known[t]);return e}declare(){let e={};for(let[a,l]of Object.entries(this.getTerms()))l instanceof m&&(e[a]=l);let t={},n=1;for(let a in y){if(!(e[a]instanceof m))continue;for(;"tmp"+n in e;)n++;let l=new m("tmp"+n,e[a]);t[l.name]=e[a],e[l.name]=l,delete e[a]}let s=O(void 0,e).list,i=new Map;if(Object.keys(t).length){let a=l=>l.traverse(h=>{if(!(h instanceof m))return null;let f=i.get(h);return f||new m(h.name,a(h.impl))})??l;for(let l=0;l<s.length;l++)s[l]=a(s[l]),i.set(t[s[l].name],s[l]),e[s[l].name]=s[l]}let o=s.map(a=>t[a.name]?a.name+"="+t[a.name].name+"="+a.impl.format({inventory:e}):a.name+"="+a.impl.format({inventory:e}));for(let[a,l]of i)o.push(a.name+"="+l,l+"=");return o}parse(e,t={}){if(typeof e!="string")throw new Error("parse: source must be a string, got "+typeof e);let n=e.replace(/\/\/[^\n]*$/gm," ").replace(/\/\*.*?\*\//gs," ").trim().split(/\s*;[\s;]*/).filter(o=>o.match(/\S/)),s={...t.env},i=new R;for(let o of n){i instanceof m&&i.makeInline();let a=o.match(/^([A-Z]|[a-z][a-z_0-9]*)\s*=(.*)$/s);if(a&&a[2]===""?i=new d(a[1],t.scope??d.global):i=this.parseLine(o,s,t),a){if(s[a[1]]!==void 0)throw new Error("Attempt to redefine a known term: "+a[1]);s[a[1]]=i}}return this.addContext&&(i instanceof v&&(i=new m(i.name,i,{inline:!0})),i.context={env:{...this.getTerms(),...s},scope:t.scope,src:e,parser:this}),i}parseLine(e,t={},n={}){let s=e.match(/^\s*([A-Z]|[a-z][a-z_0-9]*)\s*=\s*(.*)$/s);if(s)return new m(s[1],this.parseLine(s[2],t,n));let i={numbers:n.numbers??this.hasNumbers,lambdas:n.lambdas??this.hasLambdas,allow:K(this.allow,n.allow)};i.numbers?i.allow.add("+"):i.allow.delete("+");let o=We.split(e),a=new R,l=[a],h=n.scope||d.global;for(let f of o)if(f==="(")l.push(a);else if(f===")"){if(l.length<2)throw new Error("unbalanced input: extra closing parenthesis"+e);let b=ve(l.pop()),g=l.pop();l.push(g.apply(b))}else if(f==="->"){if(!i.lambdas)throw new Error("Lambdas not supported, allow them explicitly");l.push(new te(l.pop()))}else if(f.match(/^[0-9]+$/)){if(!i.numbers)throw new Error("Church numbers not supported, allow them explicitly");let b=l.pop();l.push(b.apply(new A(Number.parseInt(f))))}else{let b=l.pop();if(!t[f]&&this.known[f]&&!i.allow.has(f))throw new Error("Term '"+f+"' is not in the restricted set "+[...i.allow].sort().join(" "));let g=t[f]??this.known[f]??(t[f]=new d(f,h));l.push(b.apply(g))}if(l.length!==1)throw new Error("unbalanced input: missing "+(l.length-1)+" closing parenthesis:"+e);return ve(l.pop())}toJSON(){return{version:"1.1.1",allow:this.showRestrict("+"),numbers:this.hasNumbers,lambdas:this.hasLambdas,annotate:this.annotate,terms:this.declare()}}}});function ke(r){return r===void 0||typeof r=="string"?r:Array.isArray(r)?r.join(" "):""+r}function Je(r,e){if(r===void 0)return"missing";if(typeof r!="string"&&typeof r!="number")return"is a "+typeof r;if(e){if(e.has(r))return"duplicate id "+r;e.add(r)}}function Ee(r){if(r===void 0)return"missing";if(typeof r!="string")return"not a string but "+typeof r;let e=[],t=/<\/?([a-z]+)(?:\s[^>]*)?>/gi,n;for(;(n=t.exec(r))!==null;){let[s,i]=n;if(s.startsWith("</")){if(e.length===0||e.pop()!==i)return`Unmatched closing tag: </${i}>`}else e.push(i)}return e.length>0?`Unclosed tags: ${e.join(", ")}`:null}function ye(r,e={}){return r.traverse({},t=>t.infer(e).expr)??r}var S,N,se,Ge,re,ie,ae,oe=I(()=>{"use strict";ne();z();S=class{constructor(e){let{input:t,cases:n,allow:s,numbers:i,lambdas:o,engine:a,engineFull:l,...h}=e,f=e.env??[];this.engineFull=l??new V,this.engine=a??this.engineFull,this.restrict={allow:s,numbers:i??!1,lambdas:o??!1},this.env={};let b={};for(let g of f??[]){let p=this.engineFull.parse(g,{env:b,scope:this});if(p instanceof m)this.env[p.name]=new m(p.name,p.impl,{canonize:!1});else if(p instanceof d)this.env[p.name]=p;else throw new Error("Unsupported given variable type: "+g)}this.input=[];for(let g of Array.isArray(t)?t:[t])this.addInput(g);if(!this.input.length)throw new Error("Quest needs at least one input placeholder");this.envFull={...this.env,...b};for(let g of this.input){if(g.name in this.envFull)throw new Error("input placeholder name is duplicated or clashes with env: "+g.name);this.envFull[g.name]=g.placeholder}this.cases=[],this.name=e.name,this.intro=ke(e.intro),this.id=e.id,this.meta=h;for(let g of n??[])this.add(...g)}allowed(){let e=this.restrict.allow??"",t=Object.keys(this.env).sort();return e?this.engine.showRestrict(e+"+"+t.join(" ")):t.map(n=>"+"+n).join(" ")}addInput(e){if(typeof e!="object"&&(e={name:e}),typeof e.name!="string")throw new Error("quest 'input' field must be a string or a {name: string, ...} object");let t=e;t.placeholder=new d(e.name),this.input.push(t)}add(e,...t){let n;typeof e=="string"?(t.unshift(e),n={}):n={...e},n.engine=n.engine??this.engineFull,n.env=n.env??this.envFull;let s=this.input.map(i=>i.placeholder);return this.cases.push(n.caps?new re(s,n,t):new se(s,n,t)),this}prepare(...e){if(e.length!==this.input.length)throw new Error("Solutions provided "+e.length+" terms where "+this.input.length+" are expected");let t=0,n=[],s={...this.env};for(let i=0;i<e.length;i++){let o=this.input[i],a=this.engine.parse(e[i],{env:s,allow:o.allow??this.restrict.allow,numbers:o.numbers??this.restrict.numbers,lambdas:o.lambdas??this.restrict.lambdas}),l={...this.engine.getTerms(),...s};t+=a.fold(0,(f,b)=>{if(b instanceof v&&l[b.name]===b)return u.prune(f+1)});let h=a instanceof d?a:new m(o.fancy??o.name,a,{canonize:!1});s[o.name]=h,n.push(h)}return{prepared:n,weight:t}}check(...e){try{let{prepared:t,weight:n}=this.prepare(...e),s=this.cases.map(a=>a.check(...t)),i=s.reduce((a,l)=>a&&l.pass,!0),o=s.reduce((a,l)=>a+l.steps,0);return{expr:t[0],input:t,pass:i,steps:o,details:s,weight:n}}catch(t){return{pass:!1,details:[],exception:t,steps:0,input:e}}}verify(e){let t=this.verifyMeta(e);if(e.solutions){let n=this.verifySolutions(e.solutions);n&&(t.solutions=n)}return e.seen&&(this.id||(t.seen="No id in quest "+(this.name??"(unnamed)")),e.seen.has(this.id)&&(t.seen="Duplicate quest id "+this.id),e.seen.add(this.id)),Object.keys(t).length?t:null}verifySolutions(e){if(typeof e=="object"&&!Array.isArray(e.accepted)&&!Array.isArray(e.rejected)&&(!this.id||!e[this.id]))return null;let t=this.id!==void 0?e[this.id]:void 0,{accepted:n=[],rejected:s=[]}=t??e,i={shouldPass:[],shouldFail:[]};for(let o of n){let a=this.check(...o);a.pass||i.shouldPass.push({input:o,result:a})}for(let o of s){let a=this.check(...o);a.pass&&i.shouldFail.push({input:o,result:a})}return i.shouldFail.length+i.shouldPass.length?i:null}verifyMeta(e={}){let t={};for(let n of["name","intro"]){let s=Ee(this[n]);s&&(t[n]=s)}if(e.date){let n=new Date(this.meta?.created_at);isNaN(n.getTime())?t.date="invalid date format: "+this.meta?.created_at:(n.getTime()<new Date("2024-07-15").getTime()||n.getTime()>new Date().getTime())&&(t.date="date out of range: "+this.meta?.created_at)}return t}show(){return[...this.cases]}},N=class{constructor(e,t){this.max=t.max??1e3,this.note=t.note,this.env={...t.env??{}},this.input=e,this.engine=t.engine}parse(e){return new ie(this.engine.parse(e,{env:this.env,scope:this}),this.input)}},se=class extends N{constructor(e,t,n){if(n.length!==2)throw new Error("Case accepts exactly 2 strings");super(e,t),this.canonize=t.canonize,[this.e1,this.e2]=n.map(s=>this.parse(s))}check(...e){let t=this.e1.apply(e),n=t.run({max:this.max}),i=this.e2.apply(e).run({max:this.max}),o=null;return!n.final||!i.final?o="failed to reach normal form in "+this.max+" steps":o=this.canonize?ye(n.expr,this.canonize).diff(ye(i.expr,this.canonize)):n.expr.diff(i.expr),{pass:!o,reason:o??void 0,steps:n.steps,start:t,found:n.expr,expected:i.expr,note:this.note,args:e,case:this}}},Ge={normal:!0,proper:!0,discard:!0,duplicate:!0,linear:!0,affine:!0,arity:!0},re=class extends N{constructor(e,t,n){if(super(e,t),n.length>1)throw new Error("PropertyCase accepts exactly 1 string");if(!t.caps||typeof t.caps!="object"||!Object.keys(t.caps).length)throw new Error("PropertyCase requires a caps object with at least one capability");let s=Object.keys(t.caps).filter(i=>!Ge[i]);if(s.length)throw new Error("PropertyCase: don't know how to test these capabilities: "+s.join(", "));this.expr=this.parse(n[0]),this.caps={...t.caps},this.caps.linear&&(delete this.caps.linear,this.caps.duplicate=!1,this.caps.discard=!1,this.caps.normal=!0),this.caps.affine&&(delete this.caps.affine,this.isAffine=!0)}check(...e){let t=this.expr.apply(e),n=t.run({max:this.max}),s=n.expr.infer({max:this.max}),i=[];for(let o in this.caps)s[o]!==this.caps[o]&&i.push("expected property "+o+" to be "+this.caps[o]+", found "+s[o]);if(this.isAffine){let o=t.fold(void 0,(a,l)=>{if(l instanceof T||l instanceof d)return;let h=l.infer({max:this.max});if(!h.expr||h.duplicate)return u.stop({expr:l,props:h});if(l instanceof m&&e.indexOf(l)<0)return u.prune(a)});o&&i.push("found unexpected subterm "+o.expr+(o.props.expr?" that duplicates arguments":" without a normal form"))}return{pass:!i.length,reason:i.length?i.join(`
|
|
6
|
-
`):void 0,steps:n.steps,start:t,found:n.expr,case:this,note:this.note,args:e}}},ie=class{constructor(e,t){this.expr=e,this.env=t}apply(e){if(e.length!==this.env.length)throw new Error("Subst: expected "+this.env.length+" terms, got "+e.length);let t=this.expr;for(let n=0;n<this.env.length;n++)t=t.subst(this.env[n],e[n])??t;return t}},ae=class{constructor(e){this.name=e.name,this.intro=ke(e.intro),this.id=e.id,e.content&&(this.content=e.content.map(t=>t instanceof S?t:new S(t)))}verify(e){let t={},n=Je(this.id,e.seen);n&&(t.id=n);for(let s of["name","intro"]){let i=Ee(this[s]);i&&(t[s]=i)}return t.content=this.content.map(s=>s.verify(e)),t}};S.Group=ae;S.Case=N});function Ye(r,e,t){let{depth:n=16,infer:s=!0,progressInterval:i=1e3}=e,o=s&&!e.noskip,a=[[]],l=0,h=0,f={},b=p=>{l++;let x=s?p.infer({max:e.max,maxArgs:e.maxArgs}):null;if(o&&x&&x.expr){let M=String(x.expr);if(f[M])return{res:-1,props:x};f[M]=!0}return h++,{res:t(p,x),props:x}};for(let p of r){let{res:x=0}=b(p);if(x>0)return{expr:p,total:l,probed:h,gen:1};if(x<0)continue;a[0].push(p)}let g=0;for(let p=1;p<n;p++){e.progress&&(e.progress({gen:p,total:l,probed:h,step:!0}),g=l);for(let x=0;x<p;x++)for(let me of a[p-x-1]||[])for(let M of a[x]||[]){if(l>=(e.tries??1/0))return{total:l,probed:h,gen:p,...e.retain?{cache:a}:{}};e.progress&&l-g>=i&&(e.progress({gen:p,total:l,probed:h,step:!1}),g=l);let W=me.apply(M),{res:ge,props:Q}=b(W);if((ge??0)>0)return{expr:W,total:l,probed:h,gen:p,...e.retain?{cache:a}:{}};if((ge??0)<0)continue;let G=s&&Q?(Q.expr?0:3)+(Q.dup?1:0)+(Q.proper?0:1):0;a[p+G]||(a[p+G]=[]),a[p+G].push(W)}}return{total:l,probed:h,gen:n,...e.retain?{cache:a}:{}}}function le(r,e={}){if(r instanceof w)return r.format(e);if(r instanceof S)return"Quest("+r.name+")";if(r instanceof S.Case)return"Quest.Case";if(Array.isArray(r))return r.map(n=>le(n,e));if(typeof r!="object"||r===null||r.constructor!==Object)return r;let t={};for(let n in r)t[n]=le(r[n],e);return t}function Xe(r,e={}){let t=O([r],e);return t.list.map(n=>n instanceof m?n.name+"="+n.impl.format({inventory:t.env}):n instanceof d?n.name+"=":n.format({inventory:t.env})).join("; ")}function tt(r){if(r==null)return{value:{}};if(typeof r!="object"||Array.isArray(r)||r.constructor!==Object)return{error:{object:"Format options must be an object, not "+(r?.constructor?.name??typeof r)}};let e=r,t={};for(let n in e)if(Te[n]){let s=Te[n](e[n]);s&&(t[n]=s)}else t[n]="unknown option";return Object.keys(t).length>0?{error:t}:{value:e}}var H,et,Te,ce,Se=I(()=>{"use strict";z();oe();B();H=r=>Array.isArray(r)&&r.length===2&&typeof r[0]=="string"&&typeof r[1]=="string"?void 0:"must be a pair of strings",et=r=>Array.isArray(r)&&r.length===3&&typeof r[0]=="string"&&typeof r[1]=="string"&&typeof r[2]=="string"?void 0:"must be a triplet of strings",Te={html:r=>typeof r=="boolean"?void 0:"must be a boolean",terse:r=>typeof r=="boolean"?void 0:"must be a boolean",space:r=>typeof r=="string"?void 0:"must be a string",brackets:H,var:H,around:H,redex:H,lambda:et,inventory:r=>{if(typeof r!="object"||r===null||r.constructor!==Object)return"must be an object, not "+(r?.constructor?.name??typeof r);let e=r;for(let t of Object.keys(e))if(!(e[t]instanceof w))return"key "+t+"is not an Expr"}};ce={search:Ye,deepFormat:le,declare:Xe,toposort:O,checkFormatOptions:tt}});var Ie={};Qe(Ie,{SKI:()=>P});var P,Ae,Ce=I(()=>{"use strict";z();ne();oe();B();Se();ce.toposort=O;P=class extends V{static{this.native=y}static{this.control=u}static{this.classes=we}static{this.B=y.B}static{this.C=y.C}static{this.I=y.I}static{this.K=y.K}static{this.S=y.S}static{this.W=y.W}static vars(e={}){let t={};return new Proxy(t,{get(n,s){return s in n||(n[s]=new d(s,e)),n[s]}})}static church(e){return new A(e)}static{this.extras=ce}static{this.Quest=S}},Ae=globalThis;Ae.process?.env.SKI_REPL&&(Ae.SKI=P,console.log("SKI_REPL activated, try `new SKI();`"));typeof window<"u"&&(window.SKI=P)});var Fe=L((Ht,Oe)=>{"use strict";var ue=class{constructor(e){this.ns=e+":"}save(e,t){window.localStorage.setItem(this.ns+e,JSON.stringify(t))}load(e){return JSON.parse(window.localStorage.getItem(this.ns+e))}scan(){let e=window.localStorage,t=[];for(let n=0;n<e.length;n++){let s=e.key(n);s.startsWith(this.ns)&&t.push(s.substring(this.ns.length))}return t}delete(e){window.localStorage.removeItem(this.ns+e)}};Oe.exports={Store:ue}});var pe=L((Dt,ze)=>{"use strict";function nt(...r){let e={};for(let t of r){let n=t.replace(/[A-Z]/g,s=>"-"+s.toLowerCase());if(e[t]=document.getElementById(n),!e[t])throw new Error(`View element not found: ${n}`)}return e}function st(r,e,t={},n=null){let s=document.createElement(e),{class:i,content:o,color:a,...l}=t;i&&s.classList.add(...i),o!==void 0&&(s.innerHTML=""+o),a&&(s.style.color=a);for(let[h,f]of Object.entries(l))s.setAttribute(h,f);return n&&n(s),r&&r.appendChild(s),s}function _e(r,e){e(r);for(let t of r.childNodes)_e(t,e)}function rt(r){typeof r!="string"&&(r=""+r);let e={"<":"<",">":">","&":"&"};return r.replace(/[<>&]/g,t=>e[t])}function it(r){let e={"(":"%28",")":"%29"};return encodeURIComponent(r).replace(/[()]/g,t=>e[t]).replace(/%20/g,"+")}function at(r){return decodeURIComponent((""+r).replace(/\+/g," "))}ze.exports={append:st,decode:at,encode:it,grabView:nt,sanitize:rt,traverse:_e}});var Ve=L((Zt,Re)=>{"use strict";var{append:he}=pe(),fe=class{constructor(e={}){this.options=e,this.height=e.height??5,this.running=!1,this.delay=e.delay??0,this.maxSteps=e.max??1/0,this.onStart=e.onStart??(()=>{}),this.onStop=e.onStop??(()=>{}),this.onStep=e.onStep??(()=>{}),this.engine=e.engine,this.format=e.format??{html:!0},this.generator=e.generator??(t=>t.walk()),this.set(e.expr),this.view={},this.view.parent=e.parent,this.view.scroll=e.scroll??e.parent,this.view.main=he(e.parent,"ol",{class:["ski-eval-box"]})}set(e){if(typeof e=="string")this.src=e,this.expr=this.engine.parse(e);else if(Array.isArray(e)&&e.length===2)this.src=e[0],this.expr=e[1];else if(!e)this.expr=null,this.src=null;else if(typeof e=="object"&&typeof e.format=="function")this.expr=e,this.src=e.format();else throw new Error("EvalBox.set() expects a string, Expr, or [string, Expr]");return this}start(e){this.running&&this.stop();try{e!==void 0&&this.set(e),this.seq=this.generator(this.expr)}catch(t){return console.error(t),this.stop(t.message)}return this.view.main.innerHTML="",this.onStart(),this.running=!0,this.tick(),this}stop(e){this.running=!1,this.timer&&(clearTimeout(this.timer),this.timer=null),e&&this.print(e,{class:["ski-eval-error"],line:""}),this.onStop()}resume(){this.running||!this.seq||(this.running=!0,this.onStart(),this.tick())}tick(){if(!this.running)return;let{value:e,done:t}=this.seq.next();if(e&&this.print(e.expr.format(this.format),{line:e.steps}),this.onStep(e,t||e.final),t||e.final)return this.view.last&&this.view.last.classList.add("ski-eval-success"),this.seq=null,this.stop();if(e.steps>=this.maxSteps)return this.stop("Max steps reached: "+this.maxSteps);this.timer=setTimeout(()=>this.tick(),this.delay)}remove(){this.view.parent&&(this.view.parent.removeChild(this.view.main),this.view.parent=null)}clear(){this.stop(),this.view.main.innerHTML=""}setHeight(e){this.height=e}print(e,t={}){let n=he(this.view.main,"li",t);if(t.line!==0&&!t.line?n.style["list-style"]="none":(this.view.main.style["padding-left"]=(""+t.line).length+2.5+"ch",n.value=t.line),this.view.last=n,t.raw)n.innerHTML=e;else for(he(n,"span",{class:t.class??["ski-eval-line"],color:t.color,content:e});this.view.main.children.length>this.height;)this.view.main.removeChild(this.view.main.firstChild);return this.view.scroll&&(this.view.scroll.scrollTop=n.offsetTop),n}};Re.exports={EvalBox:fe}});var Ne=L((Wt,je)=>{"use strict";var{SKI:$}=(Ce(),Ke(Ie)),{Store:ot}=Fe(),{EvalBox:lt}=Ve(),{append:c}=pe(),de=class{constructor(e){if(this.view={},this.root=e.baseUrl??".",!e.store&&!e.storePrefix)throw new Error("No storePrefix provided");this.store=e.store??new ot(e.storePrefix),this.engine=e.engine??new $(this.store.load("engine")??{annotate:!0,allow:"SKI"}),e.inventoryBox&&(this.view.inventory=e.inventoryBox,this.showKnown()),this.view.content=e.contentBox,e.indexBox&&(this.view.index=c(e.indexBox,"div",{class:["ski-quest-nav"]})),this._onSolved=e.onSolved,this._onFailed=e.onFailed,this._onTermUnlock=e.onTermUnlock,this.chapters=[]}loadFromIndex(e,t,n){fetch(this.mkLink(e)).then(s=>s.json()).then(s=>this.loadChapters(s)).then(s=>{if(n&&n(s),t){let i=document.getElementById(t);i&&i.scrollIntoView()}})}async loadChapters(e){let t=0;this.chapters=[];let n=[];for(let s of e){let i=new Z({number:++t,link:this.mkLink(s),engine:this.engine,store:this.store,onTermUnlock:o=>this.onTermUnlock(o),onSolved:o=>this._onSolved(o),onFailed:o=>this._onFailed(o)});this.chapters.push(i),i.attach(this.view.content,{placeholder:"loading chapter"+i.number+"..."}),this.view.index&&i.addLink(this.view.index),n.push(i.fetch().then(o=>{o.draw()}))}return Promise.all(n).then(()=>this)}mkLink(e){return e.match(/^\w+:\/\//)||e.match(/^[/.]/)?e:this.root+"/"+e}onTermUnlock(e){this.engine.maybeAdd(e.name,e.impl),this.store&&this.store.save("engine",this.engine),this.showKnown(),this._onTermUnlock&&this._onTermUnlock(e)}showKnown(){if(!this.view.inventory)return;this.view.inventory.innerHTML="";let e=c(this.view.inventory,"ul",{class:["ski-quest-inventory"]}),t=this.engine.getTerms();for(let n of Object.keys(t).sort().map(s=>[s,t[s]])){let s=c(e,"li",{},i=>{i.dataset.skiTerm=n[0]});c(s,"span",{content:n[0],class:["ski-quest-term-name"]}),c(s,"span",{content:": "}),c(s,"span",{content:pt(n[1]),class:["ski-quest-term-def"]})}}demolish(){for(let e of this.store.scan())this.store.delete(e)}},D=class{constructor(e,t){let n=t.engine??t.chapter?.engine;if(!n)throw new Error("QuestBox requires an engine: SKI in either options or chapter");let s=t.store??t.chapter?.store;if(!s)throw new Error("QuestBox requires a store: Store in either options or chapter");this.impl=new $.Quest({...e,engine:n}),this.name=this.impl.id?"quest-"+this.impl.id:"",this.chapter=t.chapter,this.chapter&&t.number&&(this.number=this.chapter.number+"."+t.number),this.store=s,this.engine=n,this.view={},this.input=[]}load(){let e=this.store.load(this.name)??{};return this.status={solved:e.solved??!1,steps:e.steps??0,attempts:e.attempts??0,weight:e.weight??0,total:e.total??0},this.status.solved&&this.onSolved(),this}save(){return this.store.save(this.name,this.status),this}update(e){this.status.solved||(this.status.attempts++,this.status.total+=e.steps,this.status.steps=e.steps,this.status.weight=e.weight,e.pass&&(this.status.solved=!0,this.onSolved(e)),this.save(),this.showStatus())}onSolved(e){if(this.impl.meta.unlock&&e){let t=new $.classes.Alias(this.impl.meta.unlock,e.expr.expand());this.chapter?.onTermUnlock(t)}this.chapter&&this.chapter.addSolved(this.impl.id)}check(){this.view.display&&(this.view.display.innerHTML="running...");let e=this.input.map(n=>n.value),t=this.impl.check(...e);this.showResult(t),this.update(t)}draw(e){this.view.frame=c(e,"div",{class:["ski-quest-box"]}),this.view.frame.id=this.name;let t=c(this.view.frame,"h3"),n=c(this.view.frame,"div"),s=c(t,"a",{content:this.number?"#"+this.number:"Quest"});s.href="#"+this.name,s.onclick=()=>qe(n,!0),c(t,"span",{content:" "+this.impl.name});let i=this.impl.allowed();i&&c(t,"span",{content:" ["+i+"]"}),this.view.stat=c(t,"span",{class:["ski-quest-float-right"]});let o=c(n,"div");c(o,"div",{content:Le(this.impl.intro),class:["ski-quest-intro"]}),this.impl.meta.hint&&ct(o," Hint:..."," Hint: "+this.impl.meta.hint),this.view.display=c(n,"div",{class:["ski-quest-display"],content:"....."}),this.view.solution=c(n,"div",{class:["ski-quest-input"]}),this.drawInput(this.view.solution),this.showStatus()}drawInput(e){let t=this.impl.input,n=t.length!==1;for(let i of t){if(n){let a=c(e,"div",{class:["ski-quest-label"]});c(a,"b",{content:i.name}),i.note&&c(a,"span",{content:" // "+i.note,class:["ski-quest-comment"]})}let o=c(e,"input");o.type="text",o.onkeydown=a=>{a.key==="Enter"&&(a.preventDefault(),this.check())},this.input.push(o),c(e,"br")}let s=c(e,"button",{content:"solve!"});s.onclick=()=>this.check()}showStatus(){if(this.view.stat&&this.status.attempts){let e="in "+this.status.attempts+(this.status.attempts===1?" try":" tries"),t=this.status.solved?"✓ "+this.status.steps+" steps/"+this.status.weight+" terms ":this.status.total+" total steps ";this.view.stat.innerHTML=t+" "+e}}showResult(e){if(!this.view.display)return;this.view.display.innerHTML="";let t=c(this.view.display,"div");c(t,"span",{content:"Your solution: "+ut(e.expr)+" "}),e.exception&&c(this.view.display,"div",{class:["ski-quest-error"],content:"Execution failed: "+e.exception});for(let n of e.details){let s=c(this.view.display,"div",{class:n.pass?["ski-quest-success"]:["ski-quest-error"]});c(s,"span",{content:n.pass?"✓ ":"✗ "}),c(s,"span",{content:`${n.start} → ${n.found} `});let i=c(s,"a",{content:`in ${n.steps} steps`,class:["ski-quest-control"]});c(s,"span",{content:" "});let o=c(s,"a",{content:" (hide)",class:["ski-quest-control"],hidden:!0});n.pass||(c(s,"br"),n.expected!==void 0&&(c(s,"span",{content:" expected: "+n.expected}),c(s,"br")),n.reason&&(c(s,"span",{content:" "+n.reason}),c(s,"br")));let a=c(s,"div",{});i.onclick=()=>{a.innerHTML="",o.hidden=!1,new lt({parent:a,engine:this.engine,height:1/0,max:n.steps+2,headless:!0}).start(n.start)},o.onclick=()=>{a.innerHTML="",o.hidden=!0}}}},Z=class{constructor(e){this.options=e,this.quests=[],this.solved=new Set,this.view={},this.number=e.number??0,this.engine=e.engine,this.store=e.store,this.onTermUnlock=e.onTermUnlock??(()=>{}),this.updateMeta()}updateMeta(e={}){this.options={...this.options,...e},this.id="chapter-"+(e.id??this.number),this.view.frame&&(this.view.frame.id=this.id),this.view.link&&(this.view.link.href="#"+this.id),this.options.name&&this.view.linkText&&(this.view.linkText.innerHTML="Chapter "+this.number+": "+this.options.name)}fetch(){return fetch(this.options.link).then(e=>e.json()).then(e=>{if(Array.isArray(e)&&(e={content:e}),!Array.isArray(e.content))throw new Error("Invalid quest list in "+this.options.link);this.updateMeta(e);let t=0;for(let n of e.content)this.quests.push(new D(n,{chapter:this,number:++t}));return this})}addSolved(e){this.solved.has(e)||(this.solved.add(e),this.showStatus())}getProgress(){return{total:this.quests.length,solved:this.solved.size,complete:this.solved.size===this.quests.length,percentage:Math.round(this.solved.size/this.quests.length*100)}}attach(e,t){return this.view.frame=c(e,"div",{class:["ski-quest-chapter"]}),this.view.frame.id=this.id,t.placeholder&&(this.view.placeholder=c(this.view.frame,"div",{content:t.placeholder})),this}draw(){this.visible=!0,this.view.placeholder?.remove();let e=c(this.view.frame,"h2"),t=c(this.view.frame,"div");c(e,"span",{content:"Chapter "+this.number+": "+this.options.name}),this.view.stat=c(e,"span",{class:["ski-quest-float-right"]}),e.onclick=()=>{qe(t,this.visible=!this.visible)},this.view.intro=c(t,"div",{content:Le(this.options.intro),class:["ski-quest-note","ski-quest-chapter-intro"]}),this.view.content=c(t,"div",{class:["ski-quest-chapter-content"]});for(let n of this.quests)n.load(),n.draw(this.view.content);this.showStatus()}showStatus(){if(!this.view.stat)return;let e=this.getProgress();this.view.stat.innerHTML="Progress: "+e.solved+"/"+e.total+" ("+e.percentage+"%)",e.complete&&this.view.stat.classList.add("success"),this.view.progressbar&&(this.view.progressbar.style.paddingRight=e.percentage+"%",this.view.progressbar.style.marginRight=-e.percentage+"%")}addLink(e){let t=c(e,"div",{class:["ski-quest-nav-item"]}),n=c(t,"a",{},s=>{s.style.display="flex"});n.href="#"+this.id,this.view.link=n,this.view.progressbar=c(n,"span",{class:["ski-quest-progressbar"]}),this.view.linkText=c(n,"span",{content:"Chapter "+this.number+"..."})}};function ct(r,e,t){let n=c(r,"span",{}),s=c(n,"span",{content:e,class:["ski-quest-hint"]});s.onclick=()=>{s.remove(),c(n,"span",{content:t})}}function Le(r){return Array.isArray(r)?r.join(" "):""+r}function ut(r){return r instanceof $.classes.Expr?r instanceof $.classes.Alias?r.name+" = "+r.expand():""+r.expand():""+r}function qe(r,e){e===void 0&&(e=r.hidden),r.hidden=!e}function pt(r){return r.note??(r.impl??r).format({html:!0,lambda:[""," ↦ ",""]})}je.exports={QuestPage:de,QuestChapter:Z,QuestBox:D}});var mt=L(()=>{var{QuestBox:ht,QuestChapter:ft,QuestPage:dt}=Ne();typeof window<"u"&&(window.QuestBox=ht,window.QuestChapter=ft,window.QuestPage=dt)});mt();})();
|
|
3
|
+
`)}_unspaced(e){return this.arg._braced(!1)?!0:this.arg._unspaced(e)}},w=class r extends v{constructor(e){if(super(),typeof e!="string"||e.length===0)throw new Error("Attempt to create a named term with improper name");this.name=e}_unspaced(e){return!!(e instanceof r&&(this.name.match(/^[A-Z+]$/)&&e.name.match(/^[a-z+]/i)||this.name.match(/^[a-z+]/i)&&e.name.match(/^[A-Z+]$/)))}formatImpl(e,t){let n=e.html?this.fancyName??this.name:this.name;return this.arity!==void 0&&this.arity>0&&this.arity<=t?e.redex[0]+n+e.redex[1]:n}},He=0,m=class r extends w{constructor(e,t){super(e),this.id=++He,this.scope=t===void 0?this:t}diff(e,t=!1){if(!(e instanceof r))return super.diff(e,t);if(this.name===e.name&&this.scope===e.scope)return null;let n=this.name+"["+this.id+"]",s=e.name+"["+e.id+"]";return t?"["+s+" != "+n+"]":"["+n+" != "+s+"]"}subst(e,t){return e instanceof r&&e.name===this.name&&e.scope===this.scope?t:null}formatImpl(e,t){let n=e.html?this.fancyName??this.name:this.name;return e.var[0]+n+e.var[1]}diag(e=""){return`${e}FreeVar: ${this.name}[${this.id}]`}static{this.global=["global"]}},z=class extends w{constructor(e,t,n={}){super(e),this.invoke=t,this.annotate({canonize:!0,...n})}},E=class r extends v{constructor(e,t){if(super(),!(e instanceof m))throw new Error("Lambda argument must be a FreeVar");let n=new m(e.name,this);this.arg=n,this.impl=t.subst(e,n)??t,this.arity=1,this.size=(t.size??1)+1}invoke(e){return this.impl.subst(this.arg,e)??this.impl}_traverse_descend(e,t){let[n,s]=k(this.impl._traverse_redo(e,t)),i=n?new r(this.arg,n):null;return s===h.stop?h.stop(i):i}any(e){return e(this)||this.impl.any(e)}_fold(e,t){let[n=e,s="descend"]=k(t(e,this));if(s===h.prune)return n;if(s===h.stop)return h.stop(n);let[i,a]=k(this.impl._fold(n,t));return a===h.stop?h.stop(i):i??n}subst(e,t){if(e===this.arg)return null;let n=this.impl.subst(e,t);return n?new r(this.arg,n):null}diff(e,t=!1){if(!(e instanceof r))return super.diff(e,t);let n=new m("t"),s=this.invoke(n).diff(e.invoke(n),t);return s?"(t->"+s+")":null}formatImpl(e,t){return(t>0?e.brackets[0]:"")+e.lambda[0]+this.arg.formatImpl(e,0)+e.lambda[1]+this.impl.formatImpl(e,0)+e.lambda[2]+(t>0?e.brackets[1]:"")}diag(e=""){return`${e}Lambda (${this.arg.name}[${this.arg.id}]):
|
|
4
|
+
`+this.impl.diag(e+" ")}_braced(e){return!0}},A=class r extends v{constructor(e){if(e=Number.parseInt(String(e)),!(e>=0))throw new Error("Church number must be a non-negative integer");super(),this.invoke=t=>n=>{let s=n;for(let i=e;i-- >0;)s=t.apply(s);return s},this.n=e,this.arity=2}diff(e,t=!1){return e instanceof r?this.n===e.n?null:t?"["+e.n+" != "+this.n+"]":"["+this.n+" != "+e.n+"]":super.diff(e,t)}_unspaced(e){return!1}formatImpl(e,t){return t>=2?e.redex[0]+this.n+e.redex[1]:this.n+""}};d=class extends w{constructor(e,t,n={}){if(super(e),!(t instanceof v))throw new Error("Attempt to create an alias for a non-expression: "+t);this.impl=t,this.annotate(n),this.invoke=Y(n.inline?0:this.arity??0)(t),this.size=t.size,n.inline&&(this.inline=!0)}makeInline(){return this.invoke=Y(0)(this.impl),this.inline=!0,this}_traverse_descend(e,t){return this.impl._traverse_redo(e,t)}any(e){return e(this)||this.impl.any(e)}_fold(e,t){let[n=e,s]=k(t(e,this));if(s===h.prune)return n;if(s===h.stop)return h.stop(n);let[i,a]=k(this.impl._fold(n,t));return a===h.stop?h.stop(i):i??n}subst(e,t){return this===e?t:this.impl.subst(e,t)}step(){return(this.arity??0)>0?{expr:this,steps:0,changed:!1}:{expr:this.impl,steps:0,changed:!0}}diff(e,t=!1){return this===e?null:e.diff(this.impl,!t)}_braced(e){return this.inline?this.impl._braced(e):!1}formatImpl(e,t){return(e.inventory?e.inventory[this.name]!==this:this.inline)?this.impl.formatImpl(e,t):super.formatImpl(e,t)}diag(e=""){return`${e}Alias (${this.name}): \\
|
|
5
|
+
`+this.impl.diag(e)}};I("I",r=>r);I("K",r=>e=>r);I("S",r=>e=>t=>r.apply(t,e.apply(t)));I("B",r=>e=>t=>r.apply(e.apply(t)));I("C",r=>e=>t=>r.apply(t).apply(e));I("W",r=>e=>r.apply(e).apply(e));I("+",r=>r instanceof A?new A(r.n+1):e=>t=>e.apply(r.apply(e,t)),{note:"Increase a Church numeral argument by 1, otherwise n => f => x => f(n f x)"});be={Expr:v,App:T,Named:w,FreeVar:m,Native:z,Lambda:E,Church:A,Alias:d}});function we(r){return r.postParse?r.postParse():r}function X(r,e){for(;e instanceof d&&e.name===r;)e=e.impl;return e instanceof w&&e.name===r?e:new d(r,e,{canonize:!0})}var R,ee,Ze,_,te=O(()=>{"use strict";J();j();R=class extends v{apply(...e){return e.length>0?e.shift().apply(...e):this}postParse(){throw new Error("Attempt to use empty expression () as a term")}formatImpl(e,t){return"()"}},ee=class r extends R{constructor(e,t={}){if(super(),this.impl=new R,e instanceof m)this.terms=[e];else if(e instanceof r){if(!(e.impl instanceof m))throw new Error("Expected FreeVar->...->FreeVar->Expr");this.terms=[...e.terms,e.impl]}else throw new Error("Expected FreeVar or PartialLambda")}apply(e,...t){if(e===null||t.length!==0)throw new Error("bad syntax in partial lambda expr");return this.impl=this.impl.apply(e),this}postParse(){let e=this.impl;for(let t=this.terms.length;t-- >0;)e=new E(this.terms[t],e);return e}};Ze=new L("[()]","[A-Z]","[a-z_][a-z_0-9]*","\\b[0-9]+\\b","->","\\+"),_=class{constructor(e={}){if(this.annotate=!!e.annotate,this.addContext=!!e.addContext,this.known={...y},this.hasNumbers=!0,this.hasLambdas=!0,this.allow=new Set(Object.keys(this.known)),Array.isArray(e.terms))this.bulkAdd(e.terms);else if(e.terms)for(let t in e.terms)(typeof e.terms[t]!="string"||!e.terms[t].match(/^Native:/))&&this.add(t,e.terms[t]);this.hasNumbers=e.numbers??!0,this.hasLambdas=e.lambdas??!0,e.allow&&this.restrict(e.allow)}add(e,t,n){let s=this._named(e,t),i=typeof n=="string"?{note:n,canonize:!1}:n??{};s.annotate({canonize:this.annotate,...i});let a=this.known[s.name];return a instanceof d&&a.makeInline(),this.known[s.name]=s,this.allow.add(s.name),this}_named(e,t){if(e instanceof w)return X(e.name,e);if(typeof e!="string")throw new Error("add(): term must be an Alias or a string");if(t===void 0)throw new Error("add(): impl must be provided when term is a string");if(typeof t=="string")return X(e,this.parse(t));if(t instanceof v)return X(e,t);if(typeof t=="function")return new z(e,t);throw new Error("add(): impl must be an Expr, a string, or a function with a signature Expr => ... => Expr")}maybeAdd(e,t){return this.known[e]?this.allow.add(e):this.add(e,t),this}bulkAdd(e){for(let t of e){let n=t.match(/^([A-Z]|[a-z][a-z_0-9]*)\s*=\s*(.*)$/s);if(!n)throw new Error("bulkAdd: invalid declaration: "+t);n[2]===""?this.remove(n[1]):this.add(n[1],this.parse(n[2]))}return this}restrict(e){return this.allow=K(this.allow,e),this}showRestrict(e="+"){let t=[],n=!0;for(let s of[...K(this.allow,e)].sort()){let i=!!s.match(/^[A-Z]$/);t.length&&!(n&&i)&&t.push(" "),t.push(s),n=i}return t.join("")}remove(e){let t=this.known[e];return t instanceof d&&t.makeInline(),delete this.known[e],this.allow.delete(e),this}getTerms(){let e={};for(let t of Object.keys(this.known))this.allow.has(t)&&(e[t]=this.known[t]);return e}declare(){let e={};for(let[o,l]of Object.entries(this.getTerms()))l instanceof d&&(e[o]=l);let t={},n=1;for(let o in y){if(!(e[o]instanceof d))continue;for(;"tmp"+n in e;)n++;let l=new d("tmp"+n,e[o]);t[l.name]=e[o],e[l.name]=l,delete e[o]}let s=C({list:Object.values(e),allow:{}}).list,i=new Map;if(Object.keys(t).length){let o=l=>l.traverse(u=>{if(!(u instanceof d))return null;let f=i.get(u);return f||new d(u.name,o(u.impl))})??l;for(let l=0;l<s.length;l++)s[l]=o(s[l]),i.set(t[s[l].name],s[l]),e[s[l].name]=s[l]}let a=s.map(o=>t[o.name]?o.name+"="+t[o.name].name+"="+o.impl.format({inventory:e}):o.name+"="+o.impl.format({inventory:e}));for(let[o,l]of i)a.push(o.name+"="+l,l+"=");return a}parse(e,t={}){if(typeof e!="string")throw new Error("parse: source must be a string, got "+typeof e);let n=e.replace(/\/\/[^\n]*$/gm," ").replace(/\/\*.*?\*\//gs," ").trim().split(/\s*;[\s;]*/).filter(a=>a.match(/\S/)),s={...t.env},i=new R;for(let a of n){let[o,l,u]=a.match(/^([A-Z]|[a-z][a-z_0-9]*)\s*=(.*)$/s)||[];l!==void 0&&(s[l]instanceof d&&s[l]!==t.env?.[l]&&s[l].makeInline(),delete s[l]),u===""?i=new m(l,t.scope??m.global):i=this.parseLine(a,s,t),l&&(s[l]=i)}return this.addContext&&(i instanceof w&&(i=new d(i.name,i,{inline:!0})),i.context={env:{...this.getTerms(),...s},scope:t.scope,src:e,parser:this}),i}parseLine(e,t={},n={}){let s=e.match(/^\s*([A-Z]|[a-z][a-z_0-9]*)\s*=\s*(.*)$/s);if(s)return new d(s[1],this.parseLine(s[2],t,n),{canonize:n.canonize});let i={numbers:n.numbers??this.hasNumbers,lambdas:n.lambdas??this.hasLambdas,allow:K(this.allow,n.allow)};i.numbers?i.allow.add("+"):i.allow.delete("+");let a=Ze.split(e),o=new R,l=[o],u=n.scope||m.global;for(let f of a)if(f==="(")l.push(o);else if(f===")"){if(l.length<2)throw new Error("unbalanced input: extra closing parenthesis"+e);let b=we(l.pop()),g=l.pop();l.push(g.apply(b))}else if(f==="->"){if(!i.lambdas)throw new Error("Lambdas not supported, allow them explicitly");l.push(new ee(l.pop()))}else if(f.match(/^[0-9]+$/)){if(!i.numbers)throw new Error("Church numbers not supported, allow them explicitly");let b=l.pop();l.push(b.apply(new A(Number.parseInt(f))))}else{let b=l.pop();if(!t[f]&&this.known[f]&&!i.allow.has(f))throw new Error("Term '"+f+"' is not in the restricted set "+[...i.allow].sort().join(" "));let g=t[f]??this.known[f]??(t[f]=new m(f,u));l.push(b.apply(g))}if(l.length!==1)throw new Error("unbalanced input: missing "+(l.length-1)+" closing parenthesis:"+e);return we(l.pop())}toJSON(){return{version:"1.1.1",allow:this.showRestrict("+"),numbers:this.hasNumbers,lambdas:this.hasLambdas,annotate:this.annotate,terms:this.declare()}}}});function ye(r){return r===void 0||typeof r=="string"?r:Array.isArray(r)?r.join(" "):""+r}function Ge(r,e){if(r===void 0)return"missing";if(typeof r!="string"&&typeof r!="number")return"is a "+typeof r;if(e){if(e.has(r))return"duplicate id "+r;e.add(r)}}function ke(r){if(r===void 0)return"missing";if(typeof r!="string")return"not a string but "+typeof r;let e=[],t=/<\/?([a-z]+)(?:\s[^>]*)?>/gi,n;for(;(n=t.exec(r))!==null;){let[s,i]=n;if(s.startsWith("</")){if(e.length===0||e.pop()!==i)return`Unmatched closing tag: </${i}>`}else e.push(i)}return e.length>0?`Unclosed tags: ${e.join(", ")}`:null}function ve(r,e={}){return r.traverse({},t=>t.infer(e).expr)??r}var S,N,ne,We,se,re,ie,ae=O(()=>{"use strict";te();j();S=class{constructor(e){let{input:t,cases:n,allow:s,numbers:i,lambdas:a,engine:o,engineFull:l,...u}=e,f=e.env??[];this.engineFull=l??new _,this.engine=o??this.engineFull,this.restrict={allow:s,numbers:i??!1,lambdas:a??!1},this.env={};let b={};for(let g of f??[]){let p=this.engineFull.parse(g,{env:b,scope:this});if(p instanceof d)this.env[p.name]=new d(p.name,p.impl,{canonize:!1});else if(p instanceof m)this.env[p.name]=p;else throw new Error("Unsupported given variable type: "+g)}this.input=[];for(let g of Array.isArray(t)?t:[t])this.addInput(g);if(!this.input.length)throw new Error("Quest needs at least one input placeholder");this.envFull={...this.env,...b};for(let g of this.input){if(g.name in this.envFull)throw new Error("input placeholder name is duplicated or clashes with env: "+g.name);this.envFull[g.name]=g.placeholder}this.cases=[],this.name=e.name,this.intro=ye(e.intro),this.id=e.id,this.meta=u;for(let g of n??[])this.add(...g)}allowed(){let e=this.restrict.allow??"",t=Object.keys(this.env).sort();return e?this.engine.showRestrict(e+"+"+t.join(" ")):t.map(n=>"+"+n).join(" ")}addInput(e){if(typeof e!="object"&&(e={name:e}),typeof e.name!="string")throw new Error("quest 'input' field must be a string or a {name: string, ...} object");let t=e;t.placeholder=new m(e.name),this.input.push(t)}add(e,...t){let n;typeof e=="string"?(t.unshift(e),n={}):n={...e},n.engine=n.engine??this.engineFull,n.env=n.env??this.envFull;let s=this.input.map(i=>i.placeholder);return this.cases.push(n.caps?new se(s,n,t):new ne(s,n,t)),this}prepare(...e){if(e.length!==this.input.length)throw new Error("Solutions provided "+e.length+" terms where "+this.input.length+" are expected");let t=0,n=[],s={...this.env};for(let i=0;i<e.length;i++){let a=this.input[i],o=this.engine.parse(e[i],{env:s,allow:a.allow??this.restrict.allow,numbers:a.numbers??this.restrict.numbers,lambdas:a.lambdas??this.restrict.lambdas}),l={...this.engine.getTerms(),...s};t+=o.fold(0,(f,b)=>{if(b instanceof w&&l[b.name]===b)return h.prune(f+1)});let u=o instanceof m?o:new d(a.fancy??a.name,o,{canonize:!1});s[a.name]=u,n.push(u)}return{prepared:n,weight:t}}check(...e){try{let{prepared:t,weight:n}=this.prepare(...e),s=this.cases.map(o=>o.check(...t)),i=s.reduce((o,l)=>o&&l.pass,!0),a=s.reduce((o,l)=>o+l.steps,0);return{expr:t[0],input:t,pass:i,steps:a,details:s,weight:n}}catch(t){return{pass:!1,details:[],exception:t,steps:0,input:e}}}verify(e){let t=this.verifyMeta(e);if(e.solutions){let n=this.verifySolutions(e.solutions);n&&(t.solutions=n)}return e.seen&&(this.id||(t.seen="No id in quest "+(this.name??"(unnamed)")),e.seen.has(this.id)&&(t.seen="Duplicate quest id "+this.id),e.seen.add(this.id)),Object.keys(t).length?t:null}verifySolutions(e){if(typeof e=="object"&&!Array.isArray(e.accepted)&&!Array.isArray(e.rejected)&&(!this.id||!e[this.id]))return null;let t=this.id!==void 0?e[this.id]:void 0,{accepted:n=[],rejected:s=[]}=t??e,i={shouldPass:[],shouldFail:[]};for(let a of n){let o=this.check(...a);o.pass||i.shouldPass.push({input:a,result:o})}for(let a of s){let o=this.check(...a);o.pass&&i.shouldFail.push({input:a,result:o})}return i.shouldFail.length+i.shouldPass.length?i:null}verifyMeta(e={}){let t={};for(let n of["name","intro"]){let s=ke(this[n]);s&&(t[n]=s)}if(e.date){let n=new Date(this.meta?.created_at);isNaN(n.getTime())?t.date="invalid date format: "+this.meta?.created_at:(n.getTime()<new Date("2024-07-15").getTime()||n.getTime()>new Date().getTime())&&(t.date="date out of range: "+this.meta?.created_at)}return t}show(){return[...this.cases]}},N=class{constructor(e,t){this.max=t.max??1e3,this.note=t.note,this.env={...t.env??{}},this.input=e,this.engine=t.engine}parse(e){return new re(this.engine.parse(e,{env:this.env,scope:this}),this.input)}},ne=class extends N{constructor(e,t,n){if(n.length!==2)throw new Error("Case accepts exactly 2 strings");super(e,t),this.canonize=t.canonize,[this.e1,this.e2]=n.map(s=>this.parse(s))}check(...e){let t=this.e1.apply(e),n=t.run({max:this.max}),i=this.e2.apply(e).run({max:this.max}),a=null;return!n.final||!i.final?a="failed to reach normal form in "+this.max+" steps":a=this.canonize?ve(n.expr,this.canonize).diff(ve(i.expr,this.canonize)):n.expr.diff(i.expr),{pass:!a,reason:a??void 0,steps:n.steps,start:t,found:n.expr,expected:i.expr,note:this.note,args:e,case:this}}},We={normal:!0,proper:!0,discard:!0,duplicate:!0,linear:!0,affine:!0,arity:!0},se=class extends N{constructor(e,t,n){if(super(e,t),n.length>1)throw new Error("PropertyCase accepts exactly 1 string");if(!t.caps||typeof t.caps!="object"||!Object.keys(t.caps).length)throw new Error("PropertyCase requires a caps object with at least one capability");let s=Object.keys(t.caps).filter(i=>!We[i]);if(s.length)throw new Error("PropertyCase: don't know how to test these capabilities: "+s.join(", "));this.expr=this.parse(n[0]),this.caps={...t.caps},this.caps.linear&&(delete this.caps.linear,this.caps.duplicate=!1,this.caps.discard=!1,this.caps.normal=!0),this.caps.affine&&(delete this.caps.affine,this.isAffine=!0)}check(...e){let t=this.expr.apply(e),n=t.run({max:this.max}),s=n.expr.infer({max:this.max}),i=[];for(let a in this.caps)s[a]!==this.caps[a]&&i.push("expected property "+a+" to be "+this.caps[a]+", found "+s[a]);if(this.isAffine){let a=t.fold(void 0,(o,l)=>{if(l instanceof T||l instanceof m)return;let u=l.infer({max:this.max});if(!u.expr||u.duplicate)return h.stop({expr:l,props:u});if(l instanceof d&&e.indexOf(l)<0)return h.prune(o)});a&&i.push("found unexpected subterm "+a.expr+(a.props.expr?" that duplicates arguments":" without a normal form"))}return{pass:!i.length,reason:i.length?i.join(`
|
|
6
|
+
`):void 0,steps:n.steps,start:t,found:n.expr,case:this,note:this.note,args:e}}},re=class{constructor(e,t){this.expr=e,this.env=t}apply(e){if(e.length!==this.env.length)throw new Error("Subst: expected "+this.env.length+" terms, got "+e.length);let t=this.expr;for(let n=0;n<this.env.length;n++)t=t.subst(this.env[n],e[n])??t;return t}},ie=class{constructor(e){this.name=e.name,this.intro=ye(e.intro),this.id=e.id,e.content&&(this.content=e.content.map(t=>t instanceof S?t:new S(t)))}verify(e){let t={},n=Ge(this.id,e.seen);n&&(t.id=n);for(let s of["name","intro"]){let i=ke(this[s]);i&&(t[s]=i)}return t.content=this.content.map(s=>s.verify(e)),t}};S.Group=ie;S.Case=N});function Je(r,e,t){let{depth:n=16,infer:s=!0,progressInterval:i=1e3}=e,a=s&&!e.noskip,o=[[]],l=0,u=0,f={},b=p=>{l++;let x=s?p.infer({max:e.max,maxArgs:e.maxArgs}):null;if(a&&x&&x.expr){let M=String(x.expr);if(f[M])return{res:-1,props:x};f[M]=!0}return u++,{res:t(p,x),props:x}};for(let p of r){let{res:x=0}=b(p);if(x>0)return{expr:p,total:l,probed:u,gen:1};if(x<0)continue;o[0].push(p)}let g=0;for(let p=1;p<n;p++){e.progress&&(e.progress({gen:p,total:l,probed:u,step:!0}),g=l);for(let x=0;x<p;x++)for(let de of o[p-x-1]||[])for(let M of o[x]||[]){if(l>=(e.tries??1/0))return{total:l,probed:u,gen:p,...e.retain?{cache:o}:{}};e.progress&&l-g>=i&&(e.progress({gen:p,total:l,probed:u,step:!1}),g=l);let Z=de.apply(M),{res:me,props:Q}=b(Z);if((me??0)>0)return{expr:Z,total:l,probed:u,gen:p,...e.retain?{cache:o}:{}};if((me??0)<0)continue;let W=s&&Q?(Q.expr?0:3)+(Q.dup?1:0)+(Q.proper?0:1):0;o[p+W]||(o[p+W]=[]),o[p+W].push(Z)}}return{total:l,probed:u,gen:n,...e.retain?{cache:o}:{}}}function oe(r,e={}){if(r instanceof v)return r.format(e);if(r instanceof S)return"Quest("+r.name+")";if(r instanceof S.Case)return"Quest.Case";if(Array.isArray(r))return r.map(n=>oe(n,e));if(typeof r!="object"||r===null||r.constructor!==Object)return r;let t={};for(let n in r)t[n]=oe(r[n],e);return t}function Ye(r,e){return r.declare({inventory:e})}function et(r){if(r==null)return{value:{}};if(typeof r!="object"||Array.isArray(r)||r.constructor!==Object)return{error:{object:"Format options must be an object, not "+(r?.constructor?.name??typeof r)}};let e=r,t={};for(let n in e)if(Ee[n]){let s=Ee[n](e[n]);s&&(t[n]=s)}else t[n]="unknown option";return Object.keys(t).length>0?{error:t}:{value:e}}var B,Xe,Ee,le,Te=O(()=>{"use strict";j();ae();B=r=>Array.isArray(r)&&r.length===2&&typeof r[0]=="string"&&typeof r[1]=="string"?void 0:"must be a pair of strings",Xe=r=>Array.isArray(r)&&r.length===3&&typeof r[0]=="string"&&typeof r[1]=="string"&&typeof r[2]=="string"?void 0:"must be a triplet of strings",Ee={html:r=>typeof r=="boolean"?void 0:"must be a boolean",terse:r=>typeof r=="boolean"?void 0:"must be a boolean",space:r=>typeof r=="string"?void 0:"must be a string",brackets:B,var:B,around:B,redex:B,lambda:Xe,inventory:r=>{if(typeof r!="object"||r===null||r.constructor!==Object)return"must be an object, not "+(r?.constructor?.name??typeof r);let e=r;for(let t of Object.keys(e))if(!(e[t]instanceof v))return"key "+t+"is not an Expr"}};le={search:Je,deepFormat:oe,declare:Ye,toposort:C,checkFormatOptions:et}});var Ae={};Me(Ae,{SKI:()=>P});var P,Se,Ie=O(()=>{"use strict";j();te();ae();Te();le.toposort=C;P=class extends _{static{this.native=y}static{this.control=h}static{this.classes=be}static{this.B=y.B}static{this.C=y.C}static{this.I=y.I}static{this.K=y.K}static{this.S=y.S}static{this.W=y.W}static vars(e={}){let t={};return new Proxy(t,{get(n,s){return s in n||(n[s]=new m(s,e)),n[s]}})}static church(e){return new A(e)}static{this.extras=le}static{this.Quest=S}},Se=globalThis;Se.process?.env.SKI_REPL&&(Se.SKI=P,console.log("SKI_REPL activated, try `new SKI();`"));typeof window<"u"&&(window.SKI=P)});var Oe=V((Qt,Ce)=>{"use strict";var ce=class{constructor(e){this.ns=e+":"}save(e,t){window.localStorage.setItem(this.ns+e,JSON.stringify(t))}load(e){return JSON.parse(window.localStorage.getItem(this.ns+e))}scan(){let e=window.localStorage,t=[];for(let n=0;n<e.length;n++){let s=e.key(n);s.startsWith(this.ns)&&t.push(s.substring(this.ns.length))}return t}delete(e){window.localStorage.removeItem(this.ns+e)}};Ce.exports={Store:ce}});var ue=V((Ut,ze)=>{"use strict";function tt(...r){let e={};for(let t of r){let n=t.replace(/[A-Z]/g,s=>"-"+s.toLowerCase());if(e[t]=document.getElementById(n),!e[t])throw new Error(`View element not found: ${n}`)}return e}function nt(r,e,t={},n=null){let s=document.createElement(e),{class:i,content:a,color:o,...l}=t;i&&s.classList.add(...i),a!==void 0&&(s.innerHTML=""+a),o&&(s.style.color=o);for(let[u,f]of Object.entries(l))s.setAttribute(u,f);return n&&n(s),r&&r.appendChild(s),s}function Fe(r,e){e(r);for(let t of r.childNodes)Fe(t,e)}function st(r){typeof r!="string"&&(r=""+r);let e={"<":"<",">":">","&":"&"};return r.replace(/[<>&]/g,t=>e[t])}function rt(r){let e={"(":"%28",")":"%29"};return encodeURIComponent(r).replace(/[()]/g,t=>e[t]).replace(/%20/g,"+")}function it(r){return decodeURIComponent((""+r).replace(/\+/g," "))}ze.exports={append:nt,decode:it,encode:rt,grabView:tt,sanitize:st,traverse:Fe}});var _e=V((Kt,Re)=>{"use strict";var{append:he}=ue(),pe=class{constructor(e={}){this.options=e,this.height=e.height??5,this.running=!1,this.delay=e.delay??0,this.maxSteps=e.max??1/0,this.onStart=e.onStart??(()=>{}),this.onStop=e.onStop??(()=>{}),this.onStep=e.onStep??(()=>{}),this.engine=e.engine,this.format=e.format??{html:!0},this.generator=e.generator??(t=>t.walk()),this.set(e.expr),this.view={},this.view.parent=e.parent,this.view.scroll=e.scroll??e.parent,this.view.main=he(e.parent,"ol",{class:["ski-eval-box"]})}set(e){if(typeof e=="string")this.src=e,this.expr=this.engine.parse(e);else if(Array.isArray(e)&&e.length===2)this.src=e[0],this.expr=e[1];else if(!e)this.expr=null,this.src=null;else if(typeof e=="object"&&typeof e.format=="function")this.expr=e,this.src=e.format();else throw new Error("EvalBox.set() expects a string, Expr, or [string, Expr]");return this}start(e){this.running&&this.stop();try{e!==void 0&&this.set(e),this.seq=this.generator(this.expr)}catch(t){return console.error(t),this.stop(t.message)}return this.view.main.innerHTML="",this.onStart(),this.running=!0,this.tick(),this}stop(e){this.running=!1,this.timer&&(clearTimeout(this.timer),this.timer=null),e&&this.print(e,{class:["ski-eval-error"],line:""}),this.onStop()}resume(){this.running||!this.seq||(this.running=!0,this.onStart(),this.tick())}tick(){if(!this.running)return;let{value:e,done:t}=this.seq.next();if(e&&this.print(e.expr.format(this.format),{line:e.steps}),this.onStep(e,t||e.final),t||e.final)return this.view.last&&this.view.last.classList.add("ski-eval-success"),this.seq=null,this.stop();if(e.steps>=this.maxSteps)return this.stop("Max steps reached: "+this.maxSteps);this.timer=setTimeout(()=>this.tick(),this.delay)}remove(){this.view.parent&&(this.view.parent.removeChild(this.view.main),this.view.parent=null)}clear(){this.stop(),this.view.main.innerHTML=""}setHeight(e){this.height=e}print(e,t={}){let n=he(this.view.main,"li",t);if(t.line!==0&&!t.line?n.style["list-style"]="none":(this.view.main.style["padding-left"]=(""+t.line).length+2.5+"ch",n.value=t.line),this.view.last=n,t.raw)n.innerHTML=e;else for(he(n,"span",{class:t.class??["ski-eval-line"],color:t.color,content:e});this.view.main.children.length>this.height;)this.view.main.removeChild(this.view.main.firstChild);return this.view.scroll&&(this.view.scroll.scrollTop=n.offsetTop),n}};Re.exports={EvalBox:pe}});var je=V((Bt,qe)=>{"use strict";var{SKI:$}=(Ie(),Ue(Ae)),{Store:at}=Oe(),{EvalBox:ot}=_e(),{append:c}=ue(),fe=class{constructor(e){if(this.view={},this.root=e.baseUrl??".",!e.store&&!e.storePrefix)throw new Error("No storePrefix provided");this.store=e.store??new at(e.storePrefix),this.engine=e.engine??new $(this.store.load("engine")??{annotate:!0,allow:"SKI"}),e.inventoryBox&&(this.view.inventory=e.inventoryBox,this.showKnown()),this.view.content=e.contentBox,e.indexBox&&(this.view.index=c(e.indexBox,"div",{class:["ski-quest-nav"]})),this._onSolved=e.onSolved,this._onFailed=e.onFailed,this._onTermUnlock=e.onTermUnlock,this.chapters=[]}loadFromIndex(e,t,n){fetch(this.mkLink(e)).then(s=>s.json()).then(s=>this.loadChapters(s)).then(s=>{if(n&&n(s),t){let i=document.getElementById(t);i&&i.scrollIntoView()}})}async loadChapters(e){let t=0;this.chapters=[];let n=[];for(let s of e){let i=new D({number:++t,link:this.mkLink(s),engine:this.engine,store:this.store,onTermUnlock:a=>this.onTermUnlock(a),onSolved:a=>this._onSolved(a),onFailed:a=>this._onFailed(a)});this.chapters.push(i),i.attach(this.view.content,{placeholder:"loading chapter"+i.number+"..."}),this.view.index&&i.addLink(this.view.index),n.push(i.fetch().then(a=>{a.draw()}))}return Promise.all(n).then(()=>this)}mkLink(e){return e.match(/^\w+:\/\//)||e.match(/^[/.]/)?e:this.root+"/"+e}onTermUnlock(e){this.engine.maybeAdd(e.name,e.impl),this.store&&this.store.save("engine",this.engine),this.showKnown(),this._onTermUnlock&&this._onTermUnlock(e)}showKnown(){if(!this.view.inventory)return;this.view.inventory.innerHTML="";let e=c(this.view.inventory,"ul",{class:["ski-quest-inventory"]}),t=this.engine.getTerms();for(let n of Object.keys(t).sort().map(s=>[s,t[s]])){let s=c(e,"li",{},i=>{i.dataset.skiTerm=n[0]});c(s,"span",{content:n[0],class:["ski-quest-term-name"]}),c(s,"span",{content:": "}),c(s,"span",{content:ut(n[1]),class:["ski-quest-term-def"]})}}demolish(){for(let e of this.store.scan())this.store.delete(e)}},H=class{constructor(e,t){let n=t.engine??t.chapter?.engine;if(!n)throw new Error("QuestBox requires an engine: SKI in either options or chapter");let s=t.store??t.chapter?.store;if(!s)throw new Error("QuestBox requires a store: Store in either options or chapter");this.impl=new $.Quest({...e,engine:n}),this.name=this.impl.id?"quest-"+this.impl.id:"",this.chapter=t.chapter,this.chapter&&t.number&&(this.number=this.chapter.number+"."+t.number),this.store=s,this.engine=n,this.view={},this.input=[]}load(){let e=this.store.load(this.name)??{};return this.status={solved:e.solved||!!e.solution,solution:e.solution,steps:e.steps??0,attempts:e.attempts??0,weight:e.weight??0,total:e.total??0},this.status.solved&&this.onSolved(),this}save(){return this.store.save(this.name,this.status),this}update(e,t){this.status.solved||(this.status.attempts++,this.status.total+=e.steps,this.status.steps=e.steps,this.status.weight=e.weight,e.pass&&(this.status.solution=t,this.onSolved(e)),this.save(),this.showStatus())}onSolved(e){if(this.impl.meta.unlock&&e){let t=new $.classes.Alias(this.impl.meta.unlock,e.expr.expand());this.chapter?.onTermUnlock(t)}this.chapter&&this.chapter.addSolved(this.impl.id)}check(){this.view.display&&(this.view.display.innerHTML="running...");let e=this.input.map(n=>n.value),t=this.impl.check(...e);this.showResult(t),this.update(t,e)}draw(e){this.view.frame=c(e,"div",{class:["ski-quest-box"]}),this.view.frame.id=this.name;let t=c(this.view.frame,"h3"),n=c(this.view.frame,"div"),s=c(t,"a",{content:this.number?"#"+this.number:"Quest"});s.href="#"+this.name,s.onclick=()=>Le(n,!0),c(t,"span",{content:" "+this.impl.name});let i=this.impl.allowed();i&&c(t,"span",{content:" ["+i+"]"}),this.view.stat=c(t,"span",{class:["ski-quest-float-right"]});let a=c(n,"div");c(a,"div",{content:Ve(this.impl.intro),class:["ski-quest-intro"]}),this.impl.meta.hint&<(a," Hint:..."," Hint: "+this.impl.meta.hint),this.view.display=c(n,"div",{class:["ski-quest-display"],content:"....."}),this.view.solution=c(n,"div",{class:["ski-quest-input"]}),this.drawInput(this.view.solution),this.showStatus()}drawInput(e){let t=this.impl.input,n=t.length!==1;for(let s of t){if(n){let a=c(e,"div",{class:["ski-quest-label"]});c(a,"b",{content:s.name}),s.note&&c(a,"span",{content:" // "+s.note,class:["ski-quest-comment"]})}let i=c(e,"input");i.type="text",i.onkeydown=a=>{a.key==="Enter"&&(a.preventDefault(),this.check())},this.input.push(i),c(e,"br")}c(e,"button",{content:"solve!"},s=>{s.onclick=()=>this.check()}),this.status.solution&&c(e,"button",{content:"reveal"},s=>{s.onclick=()=>{for(let i=0;i<this.status.solution.length;i++)this.input[i].value=this.status.solution[i]}})}showStatus(){if(this.view.stat&&this.status.attempts){let e="in "+this.status.attempts+(this.status.attempts===1?" try":" tries"),t=this.status.solved?"✓ "+this.status.steps+" steps/"+this.status.weight+" terms ":this.status.total+" total steps ";this.view.stat.innerHTML=t+" "+e}}showResult(e){if(!this.view.display)return;this.view.display.innerHTML="";let t=c(this.view.display,"div");c(t,"span",{content:"Your solution: "+ct(e.expr)+" "}),e.exception&&c(this.view.display,"div",{class:["ski-quest-error"],content:"Execution failed: "+e.exception});for(let n of e.details){let s=c(this.view.display,"div",{class:n.pass?["ski-quest-success"]:["ski-quest-error"]});c(s,"span",{content:n.pass?"✓ ":"✗ "}),c(s,"span",{content:`${n.start} → ${n.found} `});let i=c(s,"a",{content:`in ${n.steps} steps`,class:["ski-quest-control"]});c(s,"span",{content:" "});let a=c(s,"a",{content:" (hide)",class:["ski-quest-control"],hidden:!0});n.pass||(c(s,"br"),n.expected!==void 0&&(c(s,"span",{content:" expected: "+n.expected}),c(s,"br")),n.reason&&(c(s,"span",{content:" "+n.reason}),c(s,"br")));let o=c(s,"div",{});i.onclick=()=>{o.innerHTML="",a.hidden=!1,new ot({parent:o,engine:this.engine,height:1/0,max:n.steps+2,headless:!0}).start(n.start)},a.onclick=()=>{o.innerHTML="",a.hidden=!0}}}},D=class{constructor(e){this.options=e,this.quests=[],this.solved=new Set,this.view={},this.number=e.number??0,this.engine=e.engine,this.store=e.store,this.onTermUnlock=e.onTermUnlock??(()=>{}),this.updateMeta()}updateMeta(e={}){this.options={...this.options,...e},this.id="chapter-"+(e.id??this.number),this.view.frame&&(this.view.frame.id=this.id),this.view.link&&(this.view.link.href="#"+this.id),this.options.name&&this.view.linkText&&(this.view.linkText.innerHTML="Chapter "+this.number+": "+this.options.name)}fetch(){return fetch(this.options.link).then(e=>e.json()).then(e=>{if(Array.isArray(e)&&(e={content:e}),!Array.isArray(e.content))throw new Error("Invalid quest list in "+this.options.link);this.updateMeta(e);let t=0;for(let n of e.content){let s=new H(n,{chapter:this,number:++t}).load();this.quests.push(s),s.status.solved&&this.solved.add(s.impl.id)}return this.showStatus(),this})}addSolved(e){this.solved.has(e)||(this.solved.add(e),this.showStatus())}getProgress(){return{total:this.quests.length,solved:this.solved.size,complete:this.solved.size===this.quests.length,percentage:Math.round(this.solved.size/this.quests.length*100)}}attach(e,t){return this.view.frame=c(e,"div",{class:["ski-quest-chapter"]}),this.view.frame.id=this.id,t.placeholder&&(this.view.placeholder=c(this.view.frame,"div",{content:t.placeholder})),this}draw(){this.visible=!0,this.view.placeholder?.remove();let e=c(this.view.frame,"h2"),t=c(this.view.frame,"div");c(e,"span",{content:"Chapter "+this.number+": "+this.options.name}),this.view.stat=c(e,"span",{class:["ski-quest-float-right"]}),e.onclick=()=>{Le(t,this.visible=!this.visible)},this.view.intro=c(t,"div",{content:Ve(this.options.intro),class:["ski-quest-note","ski-quest-chapter-intro"]}),this.view.content=c(t,"div",{class:["ski-quest-chapter-content"]});for(let n of this.quests)n.load(),n.draw(this.view.content);this.showStatus()}showStatus(){if(!this.view.stat)return;let e=this.getProgress();this.view.stat.innerHTML="Progress: "+e.solved+"/"+e.total+" ("+e.percentage+"%)",e.complete&&this.view.stat.classList.add("success"),this.view.progressbar&&(this.view.progressbar.style.paddingRight=e.percentage+"%",this.view.progressbar.style.marginRight=-e.percentage+"%")}addLink(e){let t=c(e,"div",{class:["ski-quest-nav-item"]}),n=c(t,"a",{},s=>{s.style.display="flex"});n.href="#"+this.id,this.view.link=n,this.view.progressbar=c(n,"span",{class:["ski-quest-progressbar"]}),this.view.linkText=c(n,"span",{content:"Chapter "+this.number+"..."})}};function lt(r,e,t){let n=c(r,"span",{}),s=c(n,"span",{content:e,class:["ski-quest-hint"]});s.onclick=()=>{s.remove(),c(n,"span",{content:t})}}function Ve(r){return Array.isArray(r)?r.join(" "):""+r}function ct(r){return r instanceof $.classes.Expr?r instanceof $.classes.Alias?r.name+" = "+r.expand():""+r.expand():""+r}function Le(r,e){e===void 0&&(e=r.hidden),r.hidden=!e}function ut(r){return r.note??(r.impl??r).format({html:!0,lambda:[""," ↦ ",""]})}qe.exports={QuestPage:fe,QuestChapter:D,QuestBox:H}});var dt=V(()=>{var{QuestBox:ht,QuestChapter:pt,QuestPage:ft}=je();typeof window<"u"&&(window.QuestBox=ht,window.QuestChapter=pt,window.QuestPage=ft)});dt();})();
|
|
7
7
|
//# sourceMappingURL=ski-quest.min.js.map
|