{"version":3,"sources":["jsdelivr-header.js","/npm/@codewars/lambda-calculus@1.1.2/src/lambda-calculus.js"],"names":[],"mappings":"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","file":"/npm/@codewars/lambda-calculus@1.1.2/src/lambda-calculus.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@codewars/lambda-calculus@1.1.2/src/lambda-calculus.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/*\nLambda Calculus evaluator supporting:\n  - unlimited recursion\n  - call by need\n  - fast (ish?) evaluation\n  - shortform syntax\n\nAnd additional features:\n  - debugging aids\n  - predefined encodings\n  - purity modes\n\nWritten by\nJohanWiltink - https://github.com/JohanWiltink\nKacarott - https://github.com/Kacarott\n*/\n\n// Default options\nconst config = { verbosity: \"Calm\"    //  Calm | Concise | Loquacious | Verbose\n               , purity: \"PureLC\"     //  Let | LetRec | PureLC\n               , numEncoding: \"None\"  //  None | Church | Scott | BinaryScott\n               , enforceBinaryScottInvariant: true  //  Boolean\n               };\n\nexport function configure(cfg={}) { return Object.assign(config,cfg); }\n\nfunction union(left, right) {\n  const r = new Set(left);\n  for ( const name of right ) r.add(name);\n  return r;\n}\n\nclass V {\n  constructor(name) { this.name = name; }\n  free()            { return new Set([ this.name ]); }\n  toString()        { return this.name.toString(); }\n}\n\nclass L {\n  constructor(name, body) {\n    this.name = name;\n    this.body = body;\n  }\n  free() {\n    const r = this.body?.free?.() || new Set ;\n    r.delete(this.name);\n    return r;\n  }\n  toString() {\n    return this.body instanceof L\n      ? `\\\\ ${this.name}${this.body.toString().slice(1)}`\n      : `\\\\ ${this.name} . ${this.body.toString()}`;\n  }\n}\n\nclass A {\n  constructor(left, right) {\n    this.left = left;\n    this.right = right;\n  }\n  free() { return union( this.left?.free?.() || [] , this.right?.free?.() || [] ); }\n  toString() {\n    const left = this.left instanceof L ? `(${this.left})` : this.left ;\n    const right = this.right instanceof V ? this.right : `(${this.right})` ;\n    return `${left} ${right}`;\n  }\n}\n\nclass Env extends Map {\n  // use inherited set, get for copying references\n  // insert and retrieve values with setThunk and getValue\n  // encoding of value is a Generator Object that yields value forever - this is opaque\n  setThunk(i,val) {\n    this.set(i, function*() {\n      // console.warn(`expensively calculating ${ i }`);\n      const result = (yield val) ?? val; // If val is not A or V, then it need not be evaluated\n      while ( true ) yield result;\n    } () );\n    return this;\n  }\n  // Second argument provides an interface for storing the evaluated term inside\n  // the generator, for future accesses.\n  getValue(i, result) {\n    // console.warn(`inexpensively  fetching ${ i }`);\n    return this.get(i).next(result).value;\n  }\n}\n\n// Term and Env pair, used internally to keep track of current computation in eval\nclass Tuple {\n  constructor(term,env) { Object.assign(this,{term,env}); }\n  valueOf() { return toInt(this.term); }\n  toString() { return this.term.toString(); }\n}\n\n// Used to insert an external (JS) value into evaluation manually ( avoiding implicit number conversion )\nexport function Primitive(v) { return new Tuple(new V( \"<primitive>\" ), new Env([[ \"<primitive>\" , function*() { while ( true ) yield v; } () ]])); }\n\nconst primitives = new Env;\nprimitives.setThunk( \"trace\", new Tuple( Primitive( function(v) { console.info(String(v.term)); return v; } ), new Env ) );\n\nconst Y = new L(\"f\",new A(new L(\"x\",new A(new V(\"f\"),new A(new V(\"x\"),new V(\"x\")))),new L(\"x\",new A(new V(\"f\"),new A(new V(\"x\"),new V(\"x\"))))));\n\nexport function fromInt(n) {\n  if ( config.numEncoding === \"Church\" )\n    if ( n >= 0 )\n      return new L(\"s\", new L(\"z\", Array(n).fill().reduce( s => new A(new V(\"s\"), s), new V(\"z\")) ));\n    else {\n      if ( config.verbosity >= \"Concise\" ) console.error(`fromInt.Church: negative number ${ n }`);\n      throw new RangeError;\n    }\n  else if ( config.numEncoding === \"Scott\" ) // data Int = Zero | Succ Int\n    if ( n >= 0 )\n      return new Array(n).fill().reduce( v => new L('_', new L('f', new A(new V('f'), v))), new L('z', new L('_', new V('z'))) );\n    else {\n      if ( config.verbosity >= \"Concise\" ) console.error(`fromInt.Scott: negative number ${ n }`);\n      throw new RangeError;\n    }\n  else if ( config.numEncoding === \"BinaryScott\" ) // data Int = End | Even Int | Odd Int // LittleEndian, padding ( trailing ) 0 bits are out of spec - behaviour is undefined\n    if ( n >= 0 ) {\n      const zero = new L('z', new L('_', new L('_', new V('z'))));\n      return n ? n.toString(2).split(\"\").reduce( (z,bit) => new L('_', new L('f', new L('t', new A(new V( bit==='0' ? 'f' : 't' ), z)))), zero ) : zero ;\n    } else {\n      if ( config.verbosity >= \"Concise\" ) console.error(`fromInt.BinaryScott: negative number ${ n }`);\n      throw new RangeError;\n    }\n  else if ( config.numEncoding === \"None\" ) {\n    if ( config.verbosity >= \"Concise\" ) console.error(`fromInt.None: number ${ n }`);\n    throw new EvalError;\n  } else\n    return config.numEncoding.fromInt(n); // Custom encoding\n}\n\nconst isPadded = n => n (false) ( z => z (true) ( () => isPadded(z) ) ( () => isPadded(z) ) ) (isPadded) ; // check invariant for BinaryScott number\n\nexport function toInt(term) {\n  try {\n    if ( config.numEncoding === \"Church\" ) {\n      const succ = x => x+1 ;\n      const result = term ( succ ) ;\n      return result ( result === succ ? 0 : Primitive(0) );\n    } else if ( config.numEncoding === \"Scott\" ) {\n      let result = 0, evaluating = true;\n      while ( evaluating )\n        term ( () => evaluating = false ) ( n => () => { term = n; result++ } ) ();\n      return result;\n    } else if ( config.numEncoding === \"BinaryScott\" ) {\n      const throwOnPadding = config.enforceBinaryScottInvariant && isPadded(term);\n      let result = 0, bit = 1, evaluating = true;\n      while ( evaluating )\n        term ( () => evaluating = false ) ( n => () => { term = n; bit *= 2 } ) ( n => () => { term = n; result += bit; bit *= 2 } ) ();\n      if ( throwOnPadding ) {\n        if ( config.verbosity >= \"Concise\" ) console.error(`toInt: Binary Scott number ${ result } has zero-padding`);\n        throw new TypeError(`toInt: Binary Scott number violates invariant`);\n      }\n      return result;\n    } else if ( config.numEncoding === \"None\" )\n      return term;\n    else\n      return config.numEncoding.toInt(term); // Custom encoding\n  } catch (e) {\n    if ( ! e.message.startsWith(\"toInt:\") && config.verbosity >= \"Concise\" )\n      console.error(`toInt: ${ term } is not a number in numEncoding ${ config.numEncoding }`);\n    throw e;\n  }\n}\n\n// parse :: String -> Env { String => Term }\nexport function parse(code) {\n  function parseTerm(env,code) {\n    function wrap(name,term) {\n      const FV = term?.free?.() || new Set ; FV.delete(\"()\");\n      if ( config.purity === \"Let\" )\n        return Array.from(FV).reduce( (tm,nm) => {\n          if ( env.has(nm) ) {\n            if ( config.verbosity >= \"Verbose\" ) console.debug(`   using ${ nm } = ${ env.getValue(nm) }`);\n            tm.env.set( nm, env.get(nm) );\n            return tm;\n          } else {\n            if ( config.verbosity >= \"Concise\" ) console.error(`parse: while defining ${ name } = ${ term }`);\n            if ( nm === name )\n              throw new ReferenceError(`undefined free variable ${ nm }: direct recursive calls are not supported in Let mode`);\n            else\n              throw new ReferenceError(`undefined free variable ${ nm }`);\n          }\n        } , new Tuple( term, new Env ) );\n      else if ( config.purity===\"LetRec\" )\n        return Array.from(FV).reduce( (tm,nm) => {\n          if ( nm === name )\n            return tm;\n          else if ( env.has(nm) ) {\n            if ( config.verbosity >= \"Verbose\" ) console.debug(`   using ${ nm } = ${ env.getValue(nm) }`);\n            tm.env.set( nm, env.get(nm) );\n            return tm;\n          } else {\n            if ( config.verbosity >= \"Concise\" ) console.error(`parse: while defining ${ name } = ${ term }`);\n            throw new ReferenceError(`undefined free variable ${ nm }`);\n          }\n        } , new Tuple( FV.has(name) ? new A(Y,new L(name,term)) : term , new Env ) );\n      else if ( config.purity===\"PureLC\" )\n        if ( FV.size ) {\n          if ( config.verbosity >= \"Concise\" ) console.error(`parse: while defining ${ name } = ${ term }`);\n          throw new EvalError(`unresolvable free variable(s) ${ Array.from(FV) }: all expressions must be closed in PureLC mode`);\n        } else\n          return new Tuple( term, new Env );\n      else\n        throw new RangeError(`config.purity: unknown setting \"${ purity }\"`);\n    }\n    const letters = /[a-z]/i;\n    const digits = /\\d/;\n    const identifierChars = /[-'\\w]/;\n    const whitespace = /\\s/;\n    function error(i,msg) {\n      console.error(code);\n      console.error(' '.repeat(i) + '^');\n      console.error(msg + \" at position \" + i);\n      throw new SyntaxError(msg);\n    }\n    function sp(i) { while ( whitespace.test( code[i] || \"\" ) ) i++; return i; }\n    const expect = c => function(i) { return code[i]===c ? sp(i+1) : 0 ; } ;\n    function name(i) {\n      if ( code[i]==='_' ) {\n        while ( identifierChars.test( code[i] || \"\" ) ) i++;\n        if ( code[i]==='?' ) i++;\n        return [sp(i),\"_\"];\n      } else if ( letters.test( code[i] || \"\" ) ) {\n        let j = i+1;\n        while ( identifierChars.test( code[j] || \"\" ) ) j++;\n        if ( code[j]==='?' ) j++;\n        return [sp(j),code.slice(i,j)];\n      } else\n        return null;\n    }\n    function n(i) {\n      if ( digits.test(code[i]) ) {\n        let j = i+1;\n        while ( digits.test(code[j]) ) j++;\n        return [ sp(j), fromInt(Number(code.slice(i,j))), Number(code.slice(i,j)) ]; // return JS number in addition to LC number // negative uses this\n      } else\n        return null;\n    }\n    function v(i) {\n      const r = name(i);\n      if ( r ) {\n        const [j,termName] = r;\n        if ( termName===\"_\" ) {\n          const undef = new V(\"()\");\n          undef.defName = name(0)[1];\n          return [j,undef];\n        } else\n          return [j,new V(termName)];\n      } else\n        return null;\n    }\n    function l(i) {\n      const j = expect('\\\\')(i);\n      if ( j ) {\n        let arg, args = [];\n        let k = j;\n        while ( arg = name(k) ) {\n          [k,arg] = arg;\n          args.push(arg);\n        }\n        if ( args.length ) {\n          const l = expect('.')(k) || error(k,\"lambda: expected '.'\") ;\n          const [m,body] = term(l) || error(l,\"lambda: expected a lambda calculus term\") ;\n          return [ m, args.reduceRight( (body,arg) => new L(arg,body) , body ) ];\n        } else\n          error(k,\"lambda: expected at least one named argument\");\n      } else\n        return null;\n    }\n    function a(i) {\n      let q, r = [];\n      let j = i;\n      while ( q = paren_d(term)(j) || l(j) || v(j) || n(j) || negative(n)(j) ) {\n        [j,q] = q;\n        r.push(q);\n      }\n      if ( r.length )\n        return [ j, r.reduce( (z,term) => new A(z,term) ) ];\n      else\n        return null;\n    }\n    const negative = number => function(i) {\n      const j = expect('-')(i);\n      if ( j ) {\n        const q = number(j);\n        if ( q ) {\n          const [k,,r] = q; // act on the JS number instead of the LC number\n          return [k,fromInt(-r)];\n        } else\n          error(j,\"negative: expected a number literal\")\n      } else\n        return null;\n    }\n    const paren_d = inner => function(i) {\n      const j = expect('(')(i);\n      if ( j ) {\n        const q = inner(j);\n        if ( q ) {\n          const [k,r] = q;\n          const l = expect(')')(k) || error(k,\"paren_d: expected ')'\") ;\n          return [l,r];\n        } else {\n          const k = expect(')')(j) || error(j,\"paren_d: expected ')'\") ;\n          const undefinedTerm = new V(\"()\");\n          undefinedTerm.defName = name(0)[1];\n          return [k, undefinedTerm];\n        }\n      } else\n        return null;\n    } ;\n    const term = a;\n    function defn(i) {\n      const [j,nm] = name(i)   || error(i,\"defn: expected a name\") ;\n      const k = expect('=')(j) || error(j,\"defn: expected '='\") ;\n      const [l,tm] = term(k)   || error(k,\"defn: expected a lambda calculus term\") ;\n      return [l,[nm,tm]];\n    }\n    const [i,r] = defn(0);\n    if ( i===code.length ) {\n      const [name,term] = r;\n      if ( config.verbosity >= \"Loquacious\" )\n        console.debug(`compiled ${ name }${ config.verbosity >= \"Verbose\" ? ` = ${ term }` : \"\" }`);\n      return env.setThunk( name, wrap(name,term));\n    } else\n      error(i,\"defn: incomplete parse\");\n  }\n  return code.replace( /#.*$/gm, \"\" )                  // ignore comments\n              .replace( /\\n(?=\\s)/g, \"\" )              // continue lines\n              .split( '\\n' )                           // split lines\n              .filter( term => /\\S/.test(term) )       // skip empty lines\n              .reduce(parseTerm, new Env(primitives)); // parse lines\n}\n\nexport function compile(code) {\n  if ( typeof code !== \"string\" || ! code ) throw new TypeError(\"missing code\");\n  const env = parse(code);\n  const r = {};\n  for ( const [name] of env )\n    Object.defineProperty( r, name, { get() { return evalLC(new Tuple(new V(name), env)); }, enumerable: true } );\n  return r;\n}\n\n// Top level call, term :: Tuple\nfunction evalLC(term) {\n\n  // builds function to return to user ( representing an abstraction awaiting input )\n  function awaitArg(term, env) {\n    // callback function which will evaluate term.body in an env with the input\n    function result(arg) {\n      let argEnv;\n      if ( arg?.term && arg?.env ) ({ term: arg, env: argEnv } = arg); // if callback is passed another callback, or a term\n      const termVal = new Tuple( typeof arg === 'number' ? fromInt(arg) : arg , new Env(argEnv) );\n      if ( term.name===\"_\" )\n        return runEval( new Tuple(term.body, new Env(env)) );\n      else\n        return runEval( new Tuple(term.body, new Env(env).setThunk(term.name, termVal)) );\n    }\n    return Object.assign( result, {term,env} );\n  }\n\n  // term :: Tuple\n  // isRight :: bool (indicating whether the term is left or right side of an Application)\n  // isEvaluated :: bool (indicating whether the current term should be stored in the Env)\n  // callstack :: [String] (History of var lookups, for better error messages)\n  function runEval({term,env}) { // stack: [[term, isRight, isEvaluated]], term: LC term, env = Env { name => term }\n    const callstack = [], stack = []; // Does not persist between requests for arguments\n    while ( ! ( term instanceof L ) || stack.length > 0 ) {\n      if ( term instanceof V )\n        if ( term.name===\"()\" )\n          { printStackTrace(\"eval: evaluating undefined\", term, callstack); throw new EvalError; }\n        else {\n          callstack.push(term.name);\n          const res = env.getValue(term.name);\n          if ( ! res.env )\n            term = res;\n          else {\n            if (res.term instanceof V || res.term instanceof A)\n              // Push a frame to the stack to indicate when the value should be stored back\n              stack.push( [new Tuple( term, env ), true, true ] );\n            ({term, env} = res);\n          }\n        }\n      else if ( term instanceof A ) {\n        stack.push([ new Tuple(term.right, new Env(env)), true ]);\n        term = term.left;\n      } else if ( term instanceof L ) {\n        const [ { term: lastTerm, env: lastEnv }, isRight, isEvaluated ] = stack.pop();\n        if ( isEvaluated ) {\n          // A non-evaluated term was received from an Env, but it is now evaluated.\n          // Store it.\n          lastEnv.getValue(lastTerm.name, new Tuple(term, env));\n        } else if ( isRight ) {\n          if ( term.name !== \"_\" )\n            env = new Env(env).setThunk(term.name, new Tuple(lastTerm, lastEnv));\n          term = term.body;\n        } else { // Pass the function some other function.\n          term = lastTerm(awaitArg(term, env));\n        }\n      } else if ( term instanceof Tuple ) {\n        // for primitives\n        ({term, env} = term);\n      } else { // Not a term\n        if ( stack.length === 0 ) return term;\n        const [ { term: lastTerm, env: lastEnv }, isRight, isEvaluated ] = stack.pop();\n        if ( isEvaluated ) {\n          // A non-evaluated term was received from an Env, but it is now evaluated.\n          // Store it.\n          lastEnv.getValue(lastTerm.name, new Tuple(term, env));\n        } else if ( isRight ) {\n          stack.push([ new Tuple(term, new Env(env)), false ]);\n          term = lastTerm;\n          env = lastEnv;\n        } else { // lastTerm is a JS function\n          const res = lastTerm(term);\n          if ( res?.term )\n            ( {term, env=new Env} = res );\n          else\n            term = res;\n        }\n      }\n    }\n    // We need input\n    return awaitArg(term, env);\n  }\n  return runEval(term);\n}\n\n// Print an error, with stack trace according to verbosity level\nfunction printStackTrace(error, term, stack) {\n  if ( config.verbosity >= \"Concise\" )\n    console.error(`${ error } inside definition of ${ term.defName }`);\n\n  const stackCutoff = config.verbosity < \"Verbose\" && stack[stack.length-1] == term.defName ? stack.indexOf(term.defName) + 1 : 0 ;\n\n  if ( config.verbosity >= \"Loquacious\" )\n    console.error( stack.slice(stackCutoff).reverse().map( v => `\\twhile evaluating ${ v }`).join('\\n') );\n}\n\nObject.defineProperty( Function.prototype, \"valueOf\", { value: function valueOf() { if (this.term) return toInt(this); else return this; } } );\n"]}