eyeling 1.34.5 → 1.34.6
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/README.md +3 -90
- package/bin/eyeling.cjs +4 -56
- package/dist/browser/eyeling.browser.js +0 -1
- package/examples/context-schema-audit.n3 +1 -1
- package/eyeling.js +0 -1
- package/index.d.ts +3 -37
- package/index.js +1 -90
- package/lib/cli.js +0 -1
- package/package.json +3 -12
- package/test/packlist.test.js +0 -2
- package/test/run.js +0 -2
- package/docs/eyelang-guide.md +0 -535
- package/docs/eyelang-language-reference.md +0 -697
- package/examples/eyelang/access-control-policy.pl +0 -52
- package/examples/eyelang/ackermann.pl +0 -46
- package/examples/eyelang/age.pl +0 -28
- package/examples/eyelang/aliases-and-namespaces.pl +0 -22
- package/examples/eyelang/alignment-demo.pl +0 -44
- package/examples/eyelang/allen-interval-calculus.pl +0 -64
- package/examples/eyelang/ancestor.pl +0 -21
- package/examples/eyelang/animal.pl +0 -21
- package/examples/eyelang/annotation.pl +0 -34
- package/examples/eyelang/auroracare.pl +0 -309
- package/examples/eyelang/backward.pl +0 -12
- package/examples/eyelang/basic-monadic.pl +0 -10032
- package/examples/eyelang/bayes-diagnosis.pl +0 -108
- package/examples/eyelang/bayes-therapy.pl +0 -182
- package/examples/eyelang/beam-deflection.pl +0 -50
- package/examples/eyelang/blocks-world-planning.pl +0 -75
- package/examples/eyelang/bmi.pl +0 -232
- package/examples/eyelang/braking-safety-worlds.pl +0 -69
- package/examples/eyelang/buck-converter-design.pl +0 -78
- package/examples/eyelang/cache-performance.pl +0 -54
- package/examples/eyelang/canary-release.pl +0 -49
- package/examples/eyelang/cat-koko.pl +0 -24
- package/examples/eyelang/clinical-trial-screening.pl +0 -92
- package/examples/eyelang/combinatorics-findall-sort.pl +0 -37
- package/examples/eyelang/competitive-enzyme-kinetics.pl +0 -78
- package/examples/eyelang/complex.pl +0 -121
- package/examples/eyelang/composition-of-injective-functions-is-injective.pl +0 -50
- package/examples/eyelang/context-association.pl +0 -53
- package/examples/eyelang/context-schema-audit.pl +0 -46
- package/examples/eyelang/control-system.pl +0 -72
- package/examples/eyelang/cyclic-path.pl +0 -16
- package/examples/eyelang/d3-group.pl +0 -100
- package/examples/eyelang/dairy-energy-balance.pl +0 -65
- package/examples/eyelang/data-negotiation.pl +0 -39
- package/examples/eyelang/deep-taxonomy-10.pl +0 -115
- package/examples/eyelang/deep-taxonomy-100.pl +0 -385
- package/examples/eyelang/deep-taxonomy-1000.pl +0 -3085
- package/examples/eyelang/deep-taxonomy-10000.pl +0 -30094
- package/examples/eyelang/deep-taxonomy-100000.pl +0 -300184
- package/examples/eyelang/delfour.pl +0 -281
- package/examples/eyelang/deontic-logic.pl +0 -52
- package/examples/eyelang/derived-backward-rule.pl +0 -30
- package/examples/eyelang/derived-rule.pl +0 -27
- package/examples/eyelang/diamond-property.pl +0 -38
- package/examples/eyelang/dijkstra-findall-sort.pl +0 -44
- package/examples/eyelang/dijkstra-risk-path.pl +0 -86
- package/examples/eyelang/dijkstra.pl +0 -46
- package/examples/eyelang/dining-philosophers.pl +0 -140
- package/examples/eyelang/dog.pl +0 -25
- package/examples/eyelang/dpv-odrl-purpose-mapping.pl +0 -46
- package/examples/eyelang/drone-corridor-planner.pl +0 -51
- package/examples/eyelang/easter-computus.pl +0 -89
- package/examples/eyelang/electrical-rc-filter.pl +0 -36
- package/examples/eyelang/epidemic-policy.pl +0 -67
- package/examples/eyelang/equivalence-classes-overlap-implies-same-class.pl +0 -27
- package/examples/eyelang/eulerian-path.pl +0 -85
- package/examples/eyelang/ev-range-worlds.pl +0 -82
- package/examples/eyelang/existential-rule.pl +0 -18
- package/examples/eyelang/exoplanet-validation-worlds.pl +0 -88
- package/examples/eyelang/expression-eval.pl +0 -43
- package/examples/eyelang/family-cousins.pl +0 -65
- package/examples/eyelang/fastpow.pl +0 -53
- package/examples/eyelang/fft8-numeric.pl +0 -83
- package/examples/eyelang/fibonacci.pl +0 -53
- package/examples/eyelang/field-nitrogen-balance.pl +0 -70
- package/examples/eyelang/flandor.pl +0 -296
- package/examples/eyelang/floating-point.pl +0 -23
- package/examples/eyelang/four-color-map.pl +0 -127
- package/examples/eyelang/fundamental-theorem-arithmetic.pl +0 -113
- package/examples/eyelang/gd-step-certified.pl +0 -158
- package/examples/eyelang/gdpr-compliance.pl +0 -69
- package/examples/eyelang/good-cobbler.pl +0 -14
- package/examples/eyelang/gps.pl +0 -152
- package/examples/eyelang/graph-reachability.pl +0 -36
- package/examples/eyelang/gray-code-counter.pl +0 -48
- package/examples/eyelang/greatest-lower-bound-uniqueness.pl +0 -28
- package/examples/eyelang/group-inverse-uniqueness.pl +0 -34
- package/examples/eyelang/hamiltonian-path.pl +0 -49
- package/examples/eyelang/hamming-code.pl +0 -105
- package/examples/eyelang/hanoi.pl +0 -20
- package/examples/eyelang/heat-loss.pl +0 -51
- package/examples/eyelang/heron-theorem.pl +0 -36
- package/examples/eyelang/ideal-gas-law.pl +0 -37
- package/examples/eyelang/illegitimate-reasoning.pl +0 -88
- package/examples/eyelang/knowledge-engineering-alignment-flow.pl +0 -40
- package/examples/eyelang/law-of-cosines.pl +0 -31
- package/examples/eyelang/least-squares-regression.pl +0 -81
- package/examples/eyelang/list-collection.pl +0 -33
- package/examples/eyelang/lldm.pl +0 -78
- package/examples/eyelang/manufacturing-quality-control.pl +0 -73
- package/examples/eyelang/microgrid-dispatch.pl +0 -85
- package/examples/eyelang/monkey-bananas.pl +0 -45
- package/examples/eyelang/network-sla.pl +0 -48
- package/examples/eyelang/newton-raphson.pl +0 -49
- package/examples/eyelang/nixon-diamond.pl +0 -37
- package/examples/eyelang/observability-log-correlation.pl +0 -34
- package/examples/eyelang/odrl-dpv-fpv-trust-flow.pl +0 -43
- package/examples/eyelang/odrl-dpv-healthcare-risk-ranked.pl +0 -266
- package/examples/eyelang/odrl-dpv-risk-ranked.pl +0 -320
- package/examples/eyelang/orbital-transfer-design.pl +0 -113
- package/examples/eyelang/output/access-control-policy.pl +0 -2
- package/examples/eyelang/output/ackermann.pl +0 -12
- package/examples/eyelang/output/age.pl +0 -2
- package/examples/eyelang/output/aliases-and-namespaces.pl +0 -5
- package/examples/eyelang/output/alignment-demo.pl +0 -32
- package/examples/eyelang/output/allen-interval-calculus.pl +0 -154
- package/examples/eyelang/output/ancestor.pl +0 -6
- package/examples/eyelang/output/animal.pl +0 -4
- package/examples/eyelang/output/annotation.pl +0 -4
- package/examples/eyelang/output/auroracare.pl +0 -117
- package/examples/eyelang/output/backward.pl +0 -1
- package/examples/eyelang/output/basic-monadic.pl +0 -1518
- package/examples/eyelang/output/bayes-diagnosis.pl +0 -13
- package/examples/eyelang/output/bayes-therapy.pl +0 -23
- package/examples/eyelang/output/beam-deflection.pl +0 -5
- package/examples/eyelang/output/blocks-world-planning.pl +0 -4
- package/examples/eyelang/output/bmi.pl +0 -32
- package/examples/eyelang/output/braking-safety-worlds.pl +0 -18
- package/examples/eyelang/output/buck-converter-design.pl +0 -6
- package/examples/eyelang/output/cache-performance.pl +0 -4
- package/examples/eyelang/output/canary-release.pl +0 -5
- package/examples/eyelang/output/cat-koko.pl +0 -3
- package/examples/eyelang/output/clinical-trial-screening.pl +0 -9
- package/examples/eyelang/output/combinatorics-findall-sort.pl +0 -2
- package/examples/eyelang/output/competitive-enzyme-kinetics.pl +0 -6
- package/examples/eyelang/output/complex.pl +0 -1
- package/examples/eyelang/output/composition-of-injective-functions-is-injective.pl +0 -2
- package/examples/eyelang/output/context-association.pl +0 -3
- package/examples/eyelang/output/context-schema-audit.pl +0 -12
- package/examples/eyelang/output/control-system.pl +0 -6
- package/examples/eyelang/output/cyclic-path.pl +0 -16
- package/examples/eyelang/output/d3-group.pl +0 -2
- package/examples/eyelang/output/dairy-energy-balance.pl +0 -13
- package/examples/eyelang/output/data-negotiation.pl +0 -1
- package/examples/eyelang/output/deep-taxonomy-10.pl +0 -16
- package/examples/eyelang/output/deep-taxonomy-100.pl +0 -16
- package/examples/eyelang/output/deep-taxonomy-1000.pl +0 -16
- package/examples/eyelang/output/deep-taxonomy-10000.pl +0 -16
- package/examples/eyelang/output/deep-taxonomy-100000.pl +0 -16
- package/examples/eyelang/output/delfour.pl +0 -31
- package/examples/eyelang/output/deontic-logic.pl +0 -4
- package/examples/eyelang/output/derived-backward-rule.pl +0 -3
- package/examples/eyelang/output/derived-rule.pl +0 -2
- package/examples/eyelang/output/diamond-property.pl +0 -4
- package/examples/eyelang/output/dijkstra-findall-sort.pl +0 -2
- package/examples/eyelang/output/dijkstra-risk-path.pl +0 -29
- package/examples/eyelang/output/dijkstra.pl +0 -16
- package/examples/eyelang/output/dining-philosophers.pl +0 -350
- package/examples/eyelang/output/dog.pl +0 -1
- package/examples/eyelang/output/dpv-odrl-purpose-mapping.pl +0 -18
- package/examples/eyelang/output/drone-corridor-planner.pl +0 -17
- package/examples/eyelang/output/easter-computus.pl +0 -30
- package/examples/eyelang/output/electrical-rc-filter.pl +0 -3
- package/examples/eyelang/output/epidemic-policy.pl +0 -14
- package/examples/eyelang/output/equivalence-classes-overlap-implies-same-class.pl +0 -18
- package/examples/eyelang/output/eulerian-path.pl +0 -3
- package/examples/eyelang/output/ev-range-worlds.pl +0 -19
- package/examples/eyelang/output/existential-rule.pl +0 -2
- package/examples/eyelang/output/exoplanet-validation-worlds.pl +0 -22
- package/examples/eyelang/output/expression-eval.pl +0 -1
- package/examples/eyelang/output/family-cousins.pl +0 -28
- package/examples/eyelang/output/fastpow.pl +0 -6
- package/examples/eyelang/output/fft8-numeric.pl +0 -4
- package/examples/eyelang/output/fibonacci.pl +0 -6
- package/examples/eyelang/output/field-nitrogen-balance.pl +0 -21
- package/examples/eyelang/output/flandor.pl +0 -43
- package/examples/eyelang/output/floating-point.pl +0 -9
- package/examples/eyelang/output/four-color-map.pl +0 -3
- package/examples/eyelang/output/fundamental-theorem-arithmetic.pl +0 -9
- package/examples/eyelang/output/gd-step-certified.pl +0 -79
- package/examples/eyelang/output/gdpr-compliance.pl +0 -6
- package/examples/eyelang/output/good-cobbler.pl +0 -1
- package/examples/eyelang/output/gps.pl +0 -21
- package/examples/eyelang/output/graph-reachability.pl +0 -3
- package/examples/eyelang/output/gray-code-counter.pl +0 -1
- package/examples/eyelang/output/greatest-lower-bound-uniqueness.pl +0 -2
- package/examples/eyelang/output/group-inverse-uniqueness.pl +0 -2
- package/examples/eyelang/output/hamiltonian-path.pl +0 -121
- package/examples/eyelang/output/hamming-code.pl +0 -6
- package/examples/eyelang/output/hanoi.pl +0 -1
- package/examples/eyelang/output/heat-loss.pl +0 -5
- package/examples/eyelang/output/heron-theorem.pl +0 -4
- package/examples/eyelang/output/ideal-gas-law.pl +0 -3
- package/examples/eyelang/output/illegitimate-reasoning.pl +0 -15
- package/examples/eyelang/output/knowledge-engineering-alignment-flow.pl +0 -17
- package/examples/eyelang/output/law-of-cosines.pl +0 -3
- package/examples/eyelang/output/least-squares-regression.pl +0 -5
- package/examples/eyelang/output/list-collection.pl +0 -3
- package/examples/eyelang/output/lldm.pl +0 -6
- package/examples/eyelang/output/manufacturing-quality-control.pl +0 -6
- package/examples/eyelang/output/microgrid-dispatch.pl +0 -6
- package/examples/eyelang/output/monkey-bananas.pl +0 -5
- package/examples/eyelang/output/network-sla.pl +0 -4
- package/examples/eyelang/output/newton-raphson.pl +0 -3
- package/examples/eyelang/output/nixon-diamond.pl +0 -5
- package/examples/eyelang/output/observability-log-correlation.pl +0 -28
- package/examples/eyelang/output/odrl-dpv-fpv-trust-flow.pl +0 -9
- package/examples/eyelang/output/odrl-dpv-healthcare-risk-ranked.pl +0 -42
- package/examples/eyelang/output/odrl-dpv-risk-ranked.pl +0 -120
- package/examples/eyelang/output/orbital-transfer-design.pl +0 -7
- package/examples/eyelang/output/path-discovery.pl +0 -3
- package/examples/eyelang/output/peano-arithmetic.pl +0 -3
- package/examples/eyelang/output/peasant.pl +0 -10
- package/examples/eyelang/output/pendulum-period.pl +0 -4
- package/examples/eyelang/output/polynomial.pl +0 -14
- package/examples/eyelang/output/proof-contrapositive.pl +0 -3
- package/examples/eyelang/output/quadratic-formula.pl +0 -6
- package/examples/eyelang/output/radioactive-decay.pl +0 -5
- package/examples/eyelang/output/reusable-builtins.pl +0 -5
- package/examples/eyelang/output/riemann-hypothesis.pl +0 -12
- package/examples/eyelang/output/security-incident-correlation.pl +0 -3
- package/examples/eyelang/output/service-impact.pl +0 -11
- package/examples/eyelang/output/sieve.pl +0 -1
- package/examples/eyelang/output/skolem-functions.pl +0 -16
- package/examples/eyelang/output/socket-age.pl +0 -1
- package/examples/eyelang/output/socket-family.pl +0 -3
- package/examples/eyelang/output/socrates.pl +0 -2
- package/examples/eyelang/output/statistics-summary.pl +0 -4
- package/examples/eyelang/output/superdense-coding.pl +0 -6
- package/examples/eyelang/output/term-tools.pl +0 -6
- package/examples/eyelang/output/trust-flow-provenance-threshold.pl +0 -6
- package/examples/eyelang/output/turing.pl +0 -12
- package/examples/eyelang/output/vector-similarity.pl +0 -4
- package/examples/eyelang/output/vulnerability-impact.pl +0 -20
- package/examples/eyelang/output/witch.pl +0 -7
- package/examples/eyelang/output/wolf-goat-cabbage.pl +0 -3
- package/examples/eyelang/output/zebra.pl +0 -3
- package/examples/eyelang/path-discovery.pl +0 -45013
- package/examples/eyelang/peano-arithmetic.pl +0 -31
- package/examples/eyelang/peasant.pl +0 -30
- package/examples/eyelang/pendulum-period.pl +0 -50
- package/examples/eyelang/polynomial.pl +0 -124
- package/examples/eyelang/proof/age.pl +0 -71
- package/examples/eyelang/proof/aliases-and-namespaces.pl +0 -78
- package/examples/eyelang/proof/ancestor.pl +0 -140
- package/examples/eyelang/proof/animal.pl +0 -68
- package/examples/eyelang/proof/annotation.pl +0 -80
- package/examples/eyelang/proof/backward.pl +0 -22
- package/examples/eyelang/proof/cat-koko.pl +0 -86
- package/examples/eyelang/proof/data-negotiation.pl +0 -76
- package/examples/eyelang/proof/derived-rule.pl +0 -43
- package/examples/eyelang/proof/dog.pl +0 -31
- package/examples/eyelang/proof/electrical-rc-filter.pl +0 -105
- package/examples/eyelang/proof/existential-rule.pl +0 -40
- package/examples/eyelang/proof/floating-point.pl +0 -160
- package/examples/eyelang/proof/good-cobbler.pl +0 -16
- package/examples/eyelang/proof/group-inverse-uniqueness.pl +0 -84
- package/examples/eyelang/proof/list-collection.pl +0 -52
- package/examples/eyelang/proof/proof-contrapositive.pl +0 -78
- package/examples/eyelang/proof/socket-age.pl +0 -32
- package/examples/eyelang/proof/socket-family.pl +0 -59
- package/examples/eyelang/proof/socrates.pl +0 -38
- package/examples/eyelang/proof-contrapositive.pl +0 -27
- package/examples/eyelang/quadratic-formula.pl +0 -54
- package/examples/eyelang/radioactive-decay.pl +0 -56
- package/examples/eyelang/reusable-builtins.pl +0 -32
- package/examples/eyelang/riemann-hypothesis.pl +0 -110
- package/examples/eyelang/security-incident-correlation.pl +0 -69
- package/examples/eyelang/service-impact.pl +0 -41
- package/examples/eyelang/sieve.pl +0 -20
- package/examples/eyelang/skolem-functions.pl +0 -52
- package/examples/eyelang/socket-age.pl +0 -39
- package/examples/eyelang/socket-family.pl +0 -28
- package/examples/eyelang/socrates.pl +0 -19
- package/examples/eyelang/statistics-summary.pl +0 -54
- package/examples/eyelang/superdense-coding.pl +0 -84
- package/examples/eyelang/term-tools.pl +0 -23
- package/examples/eyelang/trust-flow-provenance-threshold.pl +0 -40
- package/examples/eyelang/turing.pl +0 -67
- package/examples/eyelang/vector-similarity.pl +0 -56
- package/examples/eyelang/vulnerability-impact.pl +0 -70
- package/examples/eyelang/witch.pl +0 -38
- package/examples/eyelang/wolf-goat-cabbage.pl +0 -56
- package/examples/eyelang/zebra.pl +0 -44
- package/eyelang.d.ts +0 -80
- package/lib/eyelang/bin.js +0 -7
- package/lib/eyelang/builtins/aggregation.js +0 -81
- package/lib/eyelang/builtins/arithmetic.js +0 -208
- package/lib/eyelang/builtins/context.js +0 -42
- package/lib/eyelang/builtins/control.js +0 -34
- package/lib/eyelang/builtins/core.js +0 -78
- package/lib/eyelang/builtins/lists.js +0 -283
- package/lib/eyelang/builtins/registry.js +0 -48
- package/lib/eyelang/builtins/strings.js +0 -234
- package/lib/eyelang/builtins/terms.js +0 -66
- package/lib/eyelang/cli.js +0 -180
- package/lib/eyelang/explain.js +0 -324
- package/lib/eyelang/hash.js +0 -294
- package/lib/eyelang/index.js +0 -47
- package/lib/eyelang/package.json +0 -3
- package/lib/eyelang/parser.js +0 -428
- package/lib/eyelang/program.js +0 -237
- package/lib/eyelang/solver.js +0 -237
- package/lib/eyelang/term.js +0 -328
package/eyelang.d.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export interface EyelangStats {
|
|
2
|
-
[key: string]: number;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export interface EyelangRunOptions {
|
|
6
|
-
proof?: boolean;
|
|
7
|
-
why?: boolean;
|
|
8
|
-
explain?: boolean;
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface EyelangRunResult {
|
|
13
|
-
stdout: string;
|
|
14
|
-
stats: EyelangStats;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface EyelangSourcePart {
|
|
18
|
-
text?: string;
|
|
19
|
-
source?: string;
|
|
20
|
-
filename?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class Program {
|
|
24
|
-
constructor(clauses?: unknown[], options?: EyelangRunOptions);
|
|
25
|
-
static parse(source: string, options?: EyelangRunOptions): Program;
|
|
26
|
-
static parseSources(sources?: Array<string | EyelangSourcePart>, options?: EyelangRunOptions): Program;
|
|
27
|
-
materializationGoals(): unknown[];
|
|
28
|
-
sourceFactLines(predicateKeys?: Set<string> | null): Set<string>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function makeProgram(clauses?: unknown[], options?: EyelangRunOptions): Program;
|
|
32
|
-
export function parseClauses(source: string, options?: EyelangRunOptions): unknown[];
|
|
33
|
-
export function parseProgramText(source: string, options?: EyelangRunOptions): unknown[];
|
|
34
|
-
|
|
35
|
-
export class Env {
|
|
36
|
-
constructor(parent?: Env | null);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export class Solver {
|
|
40
|
-
constructor(program: Program, options?: EyelangRunOptions);
|
|
41
|
-
stats: EyelangStats;
|
|
42
|
-
solve(goals: unknown[], env?: Env, depth?: number): Iterable<Env>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class BuiltinRegistry {
|
|
46
|
-
constructor();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function createDefaultRegistry(): BuiltinRegistry;
|
|
50
|
-
export function getDefaultRegistry(): BuiltinRegistry;
|
|
51
|
-
|
|
52
|
-
export function run(source: string | Program, options?: EyelangRunOptions): EyelangRunResult;
|
|
53
|
-
|
|
54
|
-
export function whyProof(program: Program, goal: unknown, options?: EyelangRunOptions): { ok: boolean; text: string };
|
|
55
|
-
export function whyNoProof(goal: unknown): string;
|
|
56
|
-
|
|
57
|
-
export const ATOM: 'atom';
|
|
58
|
-
export const VARIABLE: 'variable';
|
|
59
|
-
export const COMPOUND: 'compound';
|
|
60
|
-
export const NUMBER: 'number';
|
|
61
|
-
export const STRING: 'string';
|
|
62
|
-
export function atom(name: string): unknown;
|
|
63
|
-
export function variable(name: string): unknown;
|
|
64
|
-
export function compound(name: string, args?: unknown[]): unknown;
|
|
65
|
-
export function termToString(term: unknown, env?: Env, quoted?: boolean): string;
|
|
66
|
-
|
|
67
|
-
declare const eyelang: {
|
|
68
|
-
run: typeof run;
|
|
69
|
-
Program: typeof Program;
|
|
70
|
-
makeProgram: typeof makeProgram;
|
|
71
|
-
parseClauses: typeof parseClauses;
|
|
72
|
-
parseProgramText: typeof parseProgramText;
|
|
73
|
-
Solver: typeof Solver;
|
|
74
|
-
Env: typeof Env;
|
|
75
|
-
BuiltinRegistry: typeof BuiltinRegistry;
|
|
76
|
-
createDefaultRegistry: typeof createDefaultRegistry;
|
|
77
|
-
getDefaultRegistry: typeof getDefaultRegistry;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export default eyelang;
|
package/lib/eyelang/bin.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
// Aggregation builtins that run a inner goal and collect, count, sum, or select the best answers.
|
|
2
|
-
// Each handler clones the solver so the inner goal can enumerate independently of the outer goal.
|
|
3
|
-
import { compareTerms, copyResolved, isDecimalInteger, lexicalValue, listFromItems, numberTerm, numberTextFromDouble, parseFiniteNumber, unify } from '../term.js';
|
|
4
|
-
|
|
5
|
-
export const aggregationBuiltins = {
|
|
6
|
-
register(registry) {
|
|
7
|
-
registry.add('findall', 3, findall);
|
|
8
|
-
registry.add('countall', 2, countall);
|
|
9
|
-
registry.add('sumall', 3, sumall);
|
|
10
|
-
registry.add('aggregate_min', 5, aggregateBest(true));
|
|
11
|
-
registry.add('aggregate_max', 5, aggregateBest(false));
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function* findall({ solver, goal, env }) {
|
|
16
|
-
const [template, innerGoal, bag] = goal.args;
|
|
17
|
-
const collector = solver.cloneForInnerGoal(10000000);
|
|
18
|
-
const collected = [];
|
|
19
|
-
for (const answerEnv of collector.solve([innerGoal], env.clone(), 0)) collected.push(copyResolved(template, answerEnv));
|
|
20
|
-
const next = env.clone();
|
|
21
|
-
if (unify(bag, listFromItems(collected), next)) yield next;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function* countall({ solver, goal, env }) {
|
|
25
|
-
const [innerGoal, count] = goal.args;
|
|
26
|
-
const collector = solver.cloneForInnerGoal(10000000);
|
|
27
|
-
let n = 0;
|
|
28
|
-
for (const _ of collector.solve([innerGoal], env.clone(), 0)) n++;
|
|
29
|
-
const next = env.clone();
|
|
30
|
-
if (unify(count, numberTerm(n), next)) yield next;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function* sumall({ solver, goal, env }) {
|
|
34
|
-
const [template, innerGoal, sum] = goal.args;
|
|
35
|
-
const collector = solver.cloneForInnerGoal(10000000);
|
|
36
|
-
let intSum = 0n;
|
|
37
|
-
let floatMode = false;
|
|
38
|
-
let floatSum = 0;
|
|
39
|
-
for (const answerEnv of collector.solve([innerGoal], env.clone(), 0)) {
|
|
40
|
-
const text = lexicalValue(template, answerEnv);
|
|
41
|
-
if (text == null) return;
|
|
42
|
-
if (!floatMode && isDecimalInteger(text)) intSum += BigInt(text);
|
|
43
|
-
else {
|
|
44
|
-
const value = parseFiniteNumber(text);
|
|
45
|
-
if (value == null) return;
|
|
46
|
-
if (!floatMode) { floatSum = Number(intSum); floatMode = true; }
|
|
47
|
-
floatSum += value;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
const result = floatMode ? numberTextFromDouble(floatSum) : intSum.toString();
|
|
51
|
-
const next = env.clone();
|
|
52
|
-
if (unify(sum, numberTerm(result), next)) yield next;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function aggregateBest(wantMin) {
|
|
56
|
-
return function* ({ solver, goal, env }) {
|
|
57
|
-
const [keyTemplate, valueTemplate, innerGoal, bestKey, bestValue] = goal.args;
|
|
58
|
-
const collector = solver.cloneForInnerGoal(10000000);
|
|
59
|
-
let has = false;
|
|
60
|
-
let key = null;
|
|
61
|
-
let value = null;
|
|
62
|
-
for (const answerEnv of collector.solve([innerGoal], env.clone(), 0)) {
|
|
63
|
-
const candidateKey = copyResolved(keyTemplate, answerEnv);
|
|
64
|
-
const candidateValue = copyResolved(valueTemplate, answerEnv);
|
|
65
|
-
if (!has) {
|
|
66
|
-
has = true;
|
|
67
|
-
key = candidateKey;
|
|
68
|
-
value = candidateValue;
|
|
69
|
-
} else {
|
|
70
|
-
const cmp = compareTerms(candidateKey, key);
|
|
71
|
-
if ((wantMin && cmp < 0) || (!wantMin && cmp > 0)) {
|
|
72
|
-
key = candidateKey;
|
|
73
|
-
value = candidateValue;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (!has) return;
|
|
78
|
-
const next = env.clone();
|
|
79
|
-
if (unify(bestKey, key, next) && unify(bestValue, value, next)) yield next;
|
|
80
|
-
};
|
|
81
|
-
}
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
// Numeric builtins for integer-preserving arithmetic, floating point functions, comparisons, and ranges.
|
|
2
|
-
// The code keeps BigInt paths where possible so large eyelang integers remain exact.
|
|
3
|
-
import { compareIntegerText, deref, isDecimalInteger, lexicalValue, numberTerm, numberTextFromDouble, parseFiniteNumber, unify } from '../term.js';
|
|
4
|
-
|
|
5
|
-
const unaryNames = ['neg', 'abs', 'sin', 'cos', 'tan', 'asin', 'acos', 'sqrt', 'floor', 'ceiling', 'trunc', 'rounded', 'exp', 'log'];
|
|
6
|
-
const binaryNames = ['add', 'sub', 'mul', 'div', 'mod', 'min', 'max', 'pow', 'atan2'];
|
|
7
|
-
const compareNames = ['lt', 'gt', 'le', 'ge'];
|
|
8
|
-
|
|
9
|
-
export const arithmeticBuiltins = {
|
|
10
|
-
register(registry) {
|
|
11
|
-
for (const name of unaryNames) registry.add(name, 2, unary(name), { deterministic: true });
|
|
12
|
-
for (const name of binaryNames) registry.add(name, 3, binary(name), { deterministic: true });
|
|
13
|
-
for (const name of compareNames) registry.add(name, 2, compare(name), { deterministic: true });
|
|
14
|
-
registry.add('between', 3, between);
|
|
15
|
-
registry.add('smallest_divisor_from', 3, smallestDivisorFrom, { deterministic: true });
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
function unary(name) {
|
|
21
|
-
return function* ({ goal, env }) {
|
|
22
|
-
const text = lexicalValue(goal.args[0], env);
|
|
23
|
-
if (text == null) return;
|
|
24
|
-
let out = null;
|
|
25
|
-
if ((name === 'neg' || name === 'abs' || name === 'floor' || name === 'ceiling' || name === 'trunc' || name === 'rounded') && isDecimalInteger(text)) {
|
|
26
|
-
const value = BigInt(text);
|
|
27
|
-
if (name === 'neg') out = (-value).toString();
|
|
28
|
-
else if (name === 'abs') out = (value < 0n ? -value : value).toString();
|
|
29
|
-
else out = value.toString();
|
|
30
|
-
} else {
|
|
31
|
-
const input = parseFiniteNumber(text);
|
|
32
|
-
if (input == null) return;
|
|
33
|
-
let value;
|
|
34
|
-
if (name === 'neg') value = -input;
|
|
35
|
-
else if (name === 'abs') value = Math.abs(input);
|
|
36
|
-
else if (name === 'sin') value = Math.sin(input);
|
|
37
|
-
else if (name === 'cos') value = Math.cos(input);
|
|
38
|
-
else if (name === 'tan') value = Math.tan(input);
|
|
39
|
-
else if (name === 'asin') value = Math.asin(input);
|
|
40
|
-
else if (name === 'acos') value = Math.acos(input);
|
|
41
|
-
else if (name === 'sqrt') { if (input < 0) return; value = Math.sqrt(input); }
|
|
42
|
-
else if (name === 'floor') value = Math.floor(input);
|
|
43
|
-
else if (name === 'ceiling') value = Math.ceil(input);
|
|
44
|
-
else if (name === 'trunc') value = Math.trunc(input);
|
|
45
|
-
else if (name === 'rounded') value = Math.round(input);
|
|
46
|
-
else if (name === 'exp') value = Math.exp(input);
|
|
47
|
-
else if (name === 'log') {
|
|
48
|
-
if (input <= 0) return;
|
|
49
|
-
value = logCompat(input);
|
|
50
|
-
}
|
|
51
|
-
out = (name === 'floor' || name === 'ceiling' || name === 'trunc' || name === 'rounded')
|
|
52
|
-
? String(Math.trunc(value))
|
|
53
|
-
: numberTextFromDouble(value);
|
|
54
|
-
}
|
|
55
|
-
const next = env.clone();
|
|
56
|
-
if (out != null && unify(goal.args[1], numberTerm(out), next)) yield next;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function binary(name) {
|
|
61
|
-
return function* ({ goal, env }) {
|
|
62
|
-
const leftText = lexicalValue(goal.args[0], env);
|
|
63
|
-
const rightText = lexicalValue(goal.args[1], env);
|
|
64
|
-
if (leftText == null || rightText == null) return;
|
|
65
|
-
let out = null;
|
|
66
|
-
if (isDecimalInteger(leftText) && isDecimalInteger(rightText) && name !== 'mod' && name !== 'atan2') {
|
|
67
|
-
const a = BigInt(leftText);
|
|
68
|
-
const b = BigInt(rightText);
|
|
69
|
-
if (name === 'add') out = (a + b).toString();
|
|
70
|
-
else if (name === 'sub') out = (a - b).toString();
|
|
71
|
-
else if (name === 'mul') out = (a * b).toString();
|
|
72
|
-
else if (name === 'div') { if (b === 0n) return; out = (a / b).toString(); }
|
|
73
|
-
else if (name === 'min') out = (a <= b ? a : b).toString();
|
|
74
|
-
else if (name === 'max') out = (a >= b ? a : b).toString();
|
|
75
|
-
else if (name === 'pow') { if (b < 0n) return; out = (a ** b).toString(); }
|
|
76
|
-
} else if (name === 'mod') {
|
|
77
|
-
if (!isDecimalInteger(leftText) || !isDecimalInteger(rightText)) return;
|
|
78
|
-
const a = BigInt(leftText), b = BigInt(rightText);
|
|
79
|
-
if (b === 0n) return;
|
|
80
|
-
out = (a % b).toString();
|
|
81
|
-
} else {
|
|
82
|
-
const a = parseFiniteNumber(leftText), b = parseFiniteNumber(rightText);
|
|
83
|
-
if (a == null || b == null) return;
|
|
84
|
-
let value;
|
|
85
|
-
if (name === 'add') value = a + b;
|
|
86
|
-
else if (name === 'sub') value = a - b;
|
|
87
|
-
else if (name === 'mul') value = a * b;
|
|
88
|
-
else if (name === 'div') { if (b === 0) return; value = a / b; }
|
|
89
|
-
else if (name === 'pow') value = Math.pow(a, b);
|
|
90
|
-
else if (name === 'min') value = Math.min(a, b);
|
|
91
|
-
else if (name === 'max') value = Math.max(a, b);
|
|
92
|
-
else if (name === 'atan2') value = Math.atan2(a, b);
|
|
93
|
-
out = numberTextFromDouble(value);
|
|
94
|
-
}
|
|
95
|
-
const next = env.clone();
|
|
96
|
-
if (out != null && unify(goal.args[2], numberTerm(out), next)) yield next;
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function compare(name) {
|
|
101
|
-
return function* ({ goal, env }) {
|
|
102
|
-
const left = lexicalValue(goal.args[0], env);
|
|
103
|
-
const right = lexicalValue(goal.args[1], env);
|
|
104
|
-
if (left == null || right == null) return;
|
|
105
|
-
const cmp = compareLexicalOrNumeric(left, right);
|
|
106
|
-
const pass = name === 'lt' ? cmp < 0 : name === 'gt' ? cmp > 0 : name === 'le' ? cmp <= 0 : cmp >= 0;
|
|
107
|
-
if (pass) yield env;
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function compareLexicalOrNumeric(left, right) {
|
|
112
|
-
if (isDecimalInteger(left) && isDecimalInteger(right)) return compareIntegerText(left, right);
|
|
113
|
-
const dur = compareDuration(left, right);
|
|
114
|
-
if (dur != null) return dur;
|
|
115
|
-
const a = parseFiniteNumber(left), b = parseFiniteNumber(right);
|
|
116
|
-
if (a != null && b != null) return a < b ? -1 : a > b ? 1 : 0;
|
|
117
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function compareDuration(a, b) {
|
|
121
|
-
const pa = parseDuration(a), pb = parseDuration(b);
|
|
122
|
-
if (!pa || !pb) return null;
|
|
123
|
-
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pa[i] < pb[i] ? -1 : 1;
|
|
124
|
-
return 0;
|
|
125
|
-
}
|
|
126
|
-
function parseDuration(text) {
|
|
127
|
-
const m = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?$/.exec(text);
|
|
128
|
-
if (!m || (!m[1] && !m[2] && !m[3])) return null;
|
|
129
|
-
return [Number(m[1] ?? 0), Number(m[2] ?? 0), Number(m[3] ?? 0)];
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function* between({ goal, env }) {
|
|
133
|
-
const lowText = lexicalValue(goal.args[0], env), highText = lexicalValue(goal.args[1], env);
|
|
134
|
-
if (!isDecimalInteger(lowText) || !isDecimalInteger(highText)) return;
|
|
135
|
-
const lowNumber = Number(lowText), highNumber = Number(highText);
|
|
136
|
-
const output = deref(goal.args[2], env);
|
|
137
|
-
if (Number.isSafeInteger(lowNumber) && Number.isSafeInteger(highNumber)) {
|
|
138
|
-
if (output.type === 'var') {
|
|
139
|
-
for (let value = lowNumber; value <= highNumber; value++) {
|
|
140
|
-
const next = env.clone();
|
|
141
|
-
next.bind(output.name, numberTerm(String(value)));
|
|
142
|
-
yield next;
|
|
143
|
-
}
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
for (let value = lowNumber; value <= highNumber; value++) {
|
|
147
|
-
const next = env.clone();
|
|
148
|
-
if (unify(goal.args[2], numberTerm(String(value)), next)) yield next;
|
|
149
|
-
}
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const low = BigInt(lowText), high = BigInt(highText);
|
|
153
|
-
if (output.type === 'var') {
|
|
154
|
-
for (let value = low; value <= high; value++) {
|
|
155
|
-
const next = env.clone();
|
|
156
|
-
next.bind(output.name, numberTerm(value.toString()));
|
|
157
|
-
yield next;
|
|
158
|
-
}
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
for (let value = low; value <= high; value++) {
|
|
162
|
-
const next = env.clone();
|
|
163
|
-
if (unify(goal.args[2], numberTerm(value.toString()), next)) yield next;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function* smallestDivisorFrom({ goal, env }) {
|
|
168
|
-
const nText = lexicalValue(goal.args[0], env), dText = lexicalValue(goal.args[1], env);
|
|
169
|
-
if (!isDecimalInteger(nText) || !isDecimalInteger(dText)) return;
|
|
170
|
-
const n = BigInt(nText), start = BigInt(dText);
|
|
171
|
-
if (n < 0n || start <= 0n) return;
|
|
172
|
-
let result = n;
|
|
173
|
-
for (let c = start; c > 0n && c <= n / c; c++) {
|
|
174
|
-
if (n % c === 0n) { result = c; break; }
|
|
175
|
-
}
|
|
176
|
-
const next = env.clone();
|
|
177
|
-
if (unify(goal.args[2], numberTerm(result.toString()), next)) yield next;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const f64 = new Float64Array(1);
|
|
182
|
-
const u64 = new BigUint64Array(f64.buffer);
|
|
183
|
-
|
|
184
|
-
function nextUp(value) {
|
|
185
|
-
if (!Number.isFinite(value)) return value;
|
|
186
|
-
if (value === 0) return Number.MIN_VALUE;
|
|
187
|
-
f64[0] = value;
|
|
188
|
-
u64[0] += value > 0 ? 1n : -1n;
|
|
189
|
-
return f64[0];
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function nextDown(value) {
|
|
193
|
-
if (!Number.isFinite(value)) return value;
|
|
194
|
-
if (value === 0) return -Number.MIN_VALUE;
|
|
195
|
-
f64[0] = value;
|
|
196
|
-
u64[0] += value > 0 ? -1n : 1n;
|
|
197
|
-
return f64[0];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function logCompat(input) {
|
|
201
|
-
const value = Math.log(input);
|
|
202
|
-
// V8 and glibc libm differ by one ulp for a few values reached by the
|
|
203
|
-
// Newton-Raphson example. Align this pure-JS port with the native eyelang
|
|
204
|
-
// reference while leaving ordinary log(1), log(2), log(10), and log(e) alone.
|
|
205
|
-
if (input > 2.5 && input < 2.7182818 && value > 0.95 && value < 1.0) return nextUp(value);
|
|
206
|
-
if (input > 2.7182818 && input < 2.718281828459 && value > 0.999999999999 && value < 1.0) return nextDown(value);
|
|
207
|
-
return value;
|
|
208
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// Context builtins that treat comma conjunctions as first-class data terms.
|
|
2
|
-
// These are used by examples that construct or inspect rule bodies programmatically.
|
|
3
|
-
import { atom, deref, isConjunction, listFromItems, unify } from '../term.js';
|
|
4
|
-
|
|
5
|
-
export const contextBuiltins = {
|
|
6
|
-
register(registry) {
|
|
7
|
-
registry.add('holds', 2, holdsTerm);
|
|
8
|
-
registry.add('holds', 3, holdsParts);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function* emitContextTerm(context, term, env) {
|
|
13
|
-
context = deref(context, env);
|
|
14
|
-
if (isConjunction(context)) {
|
|
15
|
-
yield* emitContextTerm(context.args[0], term, env);
|
|
16
|
-
yield* emitContextTerm(context.args[1], term, env);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const next = env.clone();
|
|
20
|
-
if (unify(term, context, next)) yield next;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function* emitContextParts(context, name, args, env) {
|
|
24
|
-
context = deref(context, env);
|
|
25
|
-
if (isConjunction(context)) {
|
|
26
|
-
yield* emitContextParts(context.args[0], name, args, env);
|
|
27
|
-
yield* emitContextParts(context.args[1], name, args, env);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (context.type !== 'atom' && context.type !== 'compound') return;
|
|
31
|
-
const next = env.clone();
|
|
32
|
-
const argList = context.type === 'compound' ? listFromItems(context.args) : listFromItems([]);
|
|
33
|
-
if (unify(name, atom(context.name), next) && unify(args, argList, next)) yield next;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function* holdsTerm({ goal, env }) {
|
|
37
|
-
yield* emitContextTerm(goal.args[0], goal.args[1], env);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function* holdsParts({ goal, env }) {
|
|
41
|
-
yield* emitContextParts(goal.args[0], goal.args[1], goal.args[2], env);
|
|
42
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Control builtins. These intentionally use bounded nested solvers so not/1 and once/1 only ask for the answers they need.
|
|
2
|
-
export const controlBuiltins = {
|
|
3
|
-
register(registry) {
|
|
4
|
-
registry.add('not', 1, notBuiltin);
|
|
5
|
-
registry.add('once', 1, onceBuiltin);
|
|
6
|
-
registry.add('forall', 2, forallBuiltin);
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
function* notBuiltin({ solver, goal, env }) {
|
|
11
|
-
const limited = solver.cloneForInnerGoal(1);
|
|
12
|
-
let found = false;
|
|
13
|
-
for (const _ of limited.solve([goal.args[0]], env.clone(), 0)) { found = true; break; }
|
|
14
|
-
if (!found) yield env;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function* onceBuiltin({ solver, goal, env }) {
|
|
18
|
-
const limited = solver.cloneForInnerGoal(1);
|
|
19
|
-
for (const answerEnv of limited.solve([goal.args[0]], env.clone(), 0)) {
|
|
20
|
-
yield answerEnv;
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function* forallBuiltin({ solver, goal, env }) {
|
|
26
|
-
const generator = solver.cloneForInnerGoal(10000000);
|
|
27
|
-
for (const answerEnv of generator.solve([goal.args[0]], env.clone(), 0)) {
|
|
28
|
-
const checker = solver.cloneForInnerGoal(1);
|
|
29
|
-
let ok = false;
|
|
30
|
-
for (const _ of checker.solve([goal.args[1]], answerEnv.clone(), 0)) { ok = true; break; }
|
|
31
|
-
if (!ok) return;
|
|
32
|
-
}
|
|
33
|
-
yield env;
|
|
34
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// Core relational builtins that do not naturally belong to arithmetic, strings, lists, or aggregation.
|
|
2
|
-
// They are deterministic filters/projections and should avoid enumerating additional answers.
|
|
3
|
-
import { stringTerm, lexicalValue, unify } from '../term.js';
|
|
4
|
-
|
|
5
|
-
function* ok(env) { yield env; }
|
|
6
|
-
|
|
7
|
-
export const coreBuiltins = {
|
|
8
|
-
register(registry) {
|
|
9
|
-
registry.add('eq', 2, function* ({ goal, env }) {
|
|
10
|
-
const next = env.clone();
|
|
11
|
-
if (unify(goal.args[0], goal.args[1], next)) yield next;
|
|
12
|
-
}, { deterministic: true });
|
|
13
|
-
|
|
14
|
-
registry.add('neq', 2, function* ({ goal, env }) {
|
|
15
|
-
const attempt = env.clone();
|
|
16
|
-
if (!unify(goal.args[0], goal.args[1], attempt)) yield env;
|
|
17
|
-
}, { deterministic: true });
|
|
18
|
-
|
|
19
|
-
registry.add('local_time', 1, function* ({ goal, env }) {
|
|
20
|
-
const next = env.clone();
|
|
21
|
-
if (unify(goal.args[0], stringTerm(localDateText()), next)) yield next;
|
|
22
|
-
}, { deterministic: true });
|
|
23
|
-
|
|
24
|
-
registry.add('difference', 3, function* ({ goal, env }) {
|
|
25
|
-
const endText = lexicalValue(goal.args[0], env);
|
|
26
|
-
const startText = lexicalValue(goal.args[1], env);
|
|
27
|
-
if (!endText || !startText) return;
|
|
28
|
-
const end = parseISODate(endText);
|
|
29
|
-
const start = parseISODate(startText);
|
|
30
|
-
if (!end || !start || compareDateParts(end, start) < 0) return;
|
|
31
|
-
let [ey, em, ed] = end;
|
|
32
|
-
const [sy, sm, sd] = start;
|
|
33
|
-
if (ed < sd) {
|
|
34
|
-
let bm = em - 1;
|
|
35
|
-
let by = ey;
|
|
36
|
-
if (bm === 0) { bm = 12; by--; }
|
|
37
|
-
ed += daysInMonth(by, bm);
|
|
38
|
-
em--;
|
|
39
|
-
if (em === 0) { em = 12; ey--; }
|
|
40
|
-
}
|
|
41
|
-
if (em < sm) { em += 12; ey--; }
|
|
42
|
-
const duration = formatDuration(ey - sy, em - sm, ed - sd);
|
|
43
|
-
const next = env.clone();
|
|
44
|
-
if (unify(goal.args[2], stringTerm(duration), next)) yield next;
|
|
45
|
-
}, { deterministic: true });
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function localDateText() {
|
|
51
|
-
const fixed = typeof process !== 'undefined' ? process.env?.EYELANG_LOCAL_TIME : null;
|
|
52
|
-
if (fixed) return fixed;
|
|
53
|
-
|
|
54
|
-
const now = new Date();
|
|
55
|
-
const yyyy = now.getFullYear();
|
|
56
|
-
const mm = String(now.getMonth() + 1).padStart(2, '0');
|
|
57
|
-
const dd = String(now.getDate()).padStart(2, '0');
|
|
58
|
-
return `${yyyy}-${mm}-${dd}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function parseISODate(text) {
|
|
62
|
-
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(text);
|
|
63
|
-
if (!m) return null;
|
|
64
|
-
const y = Number(m[1]), mo = Number(m[2]), d = Number(m[3]);
|
|
65
|
-
if (mo < 1 || mo > 12 || d < 1 || d > daysInMonth(y, mo)) return null;
|
|
66
|
-
return [y, mo, d];
|
|
67
|
-
}
|
|
68
|
-
function daysInMonth(y, m) {
|
|
69
|
-
return [0,31,((y%4===0&&y%100!==0)||y%400===0)?29:28,31,30,31,30,31,31,30,31,30,31][m] ?? 0;
|
|
70
|
-
}
|
|
71
|
-
function compareDateParts(a, b) {
|
|
72
|
-
for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
|
73
|
-
return 0;
|
|
74
|
-
}
|
|
75
|
-
function formatDuration(y, m, d) {
|
|
76
|
-
if (y === 0 && m === 0 && d === 0) return 'P0D';
|
|
77
|
-
return `P${y ? `${y}Y` : ''}${m ? `${m}M` : ''}${d ? `${d}D` : ''}`;
|
|
78
|
-
}
|