@dallaylaen/ski-interpreter 2.5.2 → 2.6.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 CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.6.0] - 2026-03-28
9
+
10
+ ### BREAKING CHANGES
11
+
12
+ - `Alias`: `outdated` and `terminal` properties replaced by
13
+ `inline`: boolean.
14
+
15
+ ### Added
16
+
17
+ - Experimental `Alias.makeInline()` that sets the inline property
18
+ and adjusts the invocation accordingly
19
+ - (don't wait for more args if inline).
20
+
8
21
  ## [2.5.2] - 2026-03-27
9
22
 
10
23
  ### Changed
@@ -26,7 +39,7 @@ and mark its abstract/final/protected methods appropriately.
26
39
 
27
40
  ### BREAKING CHANGES
28
41
 
29
- - `affine: true` in quests now means "has no duplicating subterms" rather than "non-duplicating as a whole."
42
+ - `affine: true` in quests now means "has no duplicating subterms" rather than "non-duplicating as a whole."
30
43
  Aliases are exempted from this check, so a solution `SK`
31
44
  will not pass as S is duplicating, but `false=SK; false`
32
45
  will because `false` (as a whole term) _is_ affine.
@@ -81,7 +94,7 @@ will because `false` (as a whole term) _is_ affine.
81
94
  ### Changed
82
95
 
83
96
  - `SKI.extras.foldr` is now removed in favor of
84
- `Expr.foldBottomUp<T>(fun: (expr: Expr, args: T[]) => T): T`
97
+ `Expr.foldBottomUp<T>(fun: (expr: Expr, args: T[]) => T): T`
85
98
  with the same semantics but more descriptive name
86
99
  and simpler signature.
87
100
  _Was experimental (and still is), so not considered a breaking change._
@@ -14830,8 +14830,8 @@ var Church = class _Church extends Expr {
14830
14830
  return nargs >= 2 ? options.redex[0] + this.n + options.redex[1] : this.n + "";
14831
14831
  }
14832
14832
  };
14833
- function waitn(expr, n) {
14834
- return (arg) => n <= 1 ? expr.apply(arg) : waitn(expr.apply(arg), n - 1);
14833
+ function waitn(n) {
14834
+ return n <= 1 ? (e) => (arg) => e.apply(arg) : (e) => (arg) => waitn(n - 1)(e.apply(arg));
14835
14835
  }
14836
14836
  var Alias = class extends Named {
14837
14837
  constructor(name, impl, options = {}) {
@@ -14840,17 +14840,28 @@ var Alias = class extends Named {
14840
14840
  throw new Error("Attempt to create an alias for a non-expression: " + impl);
14841
14841
  this.impl = impl;
14842
14842
  this._setup(options);
14843
- this.terminal = options.terminal ?? this.props?.proper;
14844
- this.invoke = waitn(impl, this.arity ?? 0);
14843
+ this.invoke = waitn(options.inline ? 0 : this.arity ?? 0)(impl);
14845
14844
  this.size = impl.size;
14846
- if (options.outdated)
14847
- this.outdated = true;
14845
+ if (options.inline)
14846
+ this.inline = true;
14847
+ }
14848
+ /**
14849
+ * @desc Make the alias inline, i.e. replace it with its implementation everywhere.
14850
+ *
14851
+ * Replaces the old `outdated` attribute.
14852
+ * Used by the parser when a term definition is removed or updated.
14853
+ *
14854
+ * May change in future versions, use with caution.
14855
+ *
14856
+ * @experimental
14857
+ * @returns {this}
14858
+ */
14859
+ makeInline() {
14860
+ this.invoke = waitn(0)(this.impl);
14861
+ this.inline = true;
14862
+ return this;
14848
14863
  }
14849
14864
  /**
14850
- * @property {boolean} [outdated] - whether the alias is outdated
14851
- * and should be replaced with its definition when encountered.
14852
- * @property {boolean} [terminal] - whether the alias should behave like a standalone term
14853
- * // TODO better name?
14854
14865
  * @property {boolean} [proper] - whether the alias is a proper combinator (i.e. contains no free variables or constants)
14855
14866
  * @property {number} [arity] - the number of arguments the alias waits for before expanding
14856
14867
  * @property {Expr} [canonical] - equivalent lambda term.
@@ -14893,11 +14904,11 @@ var Alias = class extends Named {
14893
14904
  return other.diff(this.impl, !swap);
14894
14905
  }
14895
14906
  _braced(first) {
14896
- return this.outdated ? this.impl._braced(first) : false;
14907
+ return this.inline ? this.impl._braced(first) : false;
14897
14908
  }
14898
14909
  formatImpl(options, nargs) {
14899
- const outdated = options.inventory ? options.inventory[this.name] !== this : this.outdated;
14900
- return outdated ? this.impl.formatImpl(options, nargs) : super.formatImpl(options, nargs);
14910
+ const inline = options.inventory ? options.inventory[this.name] !== this : this.inline;
14911
+ return inline ? this.impl.formatImpl(options, nargs) : super.formatImpl(options, nargs);
14901
14912
  }
14902
14913
  diag(indent = "") {
14903
14914
  return `${indent}Alias (${this.name}): \\
@@ -15109,8 +15120,9 @@ var Parser = class {
15109
15120
  const named = this._named(term, impl);
15110
15121
  const opts = typeof options === "string" ? { note: options, canonize: false } : options ?? {};
15111
15122
  named._setup({ canonize: this.annotate, ...opts });
15112
- if (this.known[named.name])
15113
- this.known[named.name].outdated = true;
15123
+ const old = this.known[named.name];
15124
+ if (old instanceof Alias)
15125
+ old.makeInline();
15114
15126
  this.known[named.name] = named;
15115
15127
  this.allow.add(named.name);
15116
15128
  return this;
@@ -15210,7 +15222,9 @@ var Parser = class {
15210
15222
  * @return {SKI}
15211
15223
  */
15212
15224
  remove(name) {
15213
- this.known[name].outdated = true;
15225
+ const old = this.known[name];
15226
+ if (old instanceof Alias)
15227
+ old.makeInline();
15214
15228
  delete this.known[name];
15215
15229
  this.allow.delete(name);
15216
15230
  return this;
@@ -15295,7 +15309,7 @@ var Parser = class {
15295
15309
  let expr = new Empty();
15296
15310
  for (const item of lines) {
15297
15311
  if (expr instanceof Alias)
15298
- expr.outdated = true;
15312
+ expr.makeInline();
15299
15313
  const def = item.match(/^([A-Z]|[a-z][a-z_0-9]*)\s*=(.*)$/s);
15300
15314
  if (def && def[2] === "")
15301
15315
  expr = new FreeVar(def[1], options.scope ?? FreeVar.global);
@@ -15309,7 +15323,7 @@ var Parser = class {
15309
15323
  }
15310
15324
  if (this.addContext) {
15311
15325
  if (expr instanceof Named)
15312
- expr = new Alias(expr.name, expr, { outdated: true });
15326
+ expr = new Alias(expr.name, expr, { inline: true });
15313
15327
  expr.context = {
15314
15328
  env: { ...this.getTerms(), ...jar },
15315
15329
  // also contains pre-parsed terms
@@ -15417,7 +15431,7 @@ var Quest = class {
15417
15431
  for (const term of env ?? []) {
15418
15432
  const expr = this.engineFull.parse(term, { env: jar, scope: this });
15419
15433
  if (expr instanceof Alias)
15420
- this.env[expr.name] = new Alias(expr.name, expr.impl, { terminal: true, canonize: false });
15434
+ this.env[expr.name] = new Alias(expr.name, expr.impl, { canonize: false });
15421
15435
  else if (expr instanceof FreeVar)
15422
15436
  this.env[expr.name] = expr;
15423
15437
  else
@@ -15506,7 +15520,7 @@ var Quest = class {
15506
15520
  if (e instanceof Named && arsenal[e.name] === e)
15507
15521
  return control.prune(a + 1);
15508
15522
  });
15509
- const expr = impl instanceof FreeVar ? impl : new Alias(spec.fancy ?? spec.name, impl, { terminal: true, canonize: false });
15523
+ const expr = impl instanceof FreeVar ? impl : new Alias(spec.fancy ?? spec.name, impl, { canonize: false });
15510
15524
  jar[spec.name] = expr;
15511
15525
  prepared.push(expr);
15512
15526
  }