aontu 0.52.1 → 0.54.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/README.md +88 -0
- package/bin/aontu-mcp.js +4 -0
- package/dist/agentsmd.d.ts +16 -0
- package/dist/agentsmd.js +107 -0
- package/dist/agentsmd.js.map +1 -0
- package/dist/aontu.d.ts +15 -3
- package/dist/aontu.js +126 -5
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +45 -1
- package/dist/cli.js +2845 -69
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +18 -0
- package/dist/ctx.js +44 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.d.ts +22 -0
- package/dist/diff.js +141 -0
- package/dist/diff.js.map +1 -0
- package/dist/err.d.ts +3 -1
- package/dist/err.js +45 -8
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +13 -0
- package/dist/graph.js +110 -0
- package/dist/graph.js.map +1 -0
- package/dist/hcanon.d.ts +3 -0
- package/dist/hcanon.js +145 -0
- package/dist/hcanon.js.map +1 -0
- package/dist/hints.js +235 -8
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +20 -0
- package/dist/jsonschema.js +425 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/lang.js +955 -110
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +343 -48
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.d.ts +20 -0
- package/dist/mcp-server.js +147 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +42 -0
- package/dist/mcp.js +941 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mod-tool.d.ts +58 -0
- package/dist/mod-tool.js +532 -0
- package/dist/mod-tool.js.map +1 -0
- package/dist/mod.d.ts +35 -0
- package/dist/mod.js +345 -0
- package/dist/mod.js.map +1 -0
- package/dist/patch.d.ts +49 -0
- package/dist/patch.js +506 -0
- package/dist/patch.js.map +1 -0
- package/dist/provenance.d.ts +41 -0
- package/dist/provenance.js +336 -0
- package/dist/provenance.js.map +1 -0
- package/dist/query.d.ts +27 -0
- package/dist/query.js +294 -0
- package/dist/query.js.map +1 -0
- package/dist/reach.d.ts +15 -0
- package/dist/reach.js +168 -0
- package/dist/reach.js.map +1 -0
- package/dist/relation.d.ts +23 -0
- package/dist/relation.js +230 -0
- package/dist/relation.js.map +1 -0
- package/dist/report-sarif.d.ts +14 -0
- package/dist/report-sarif.js +102 -0
- package/dist/report-sarif.js.map +1 -0
- package/dist/sig.d.ts +25 -0
- package/dist/sig.js +277 -0
- package/dist/sig.js.map +1 -0
- package/dist/sigdecl.d.ts +2 -0
- package/dist/sigdecl.js +11 -0
- package/dist/sigdecl.js.map +1 -0
- package/dist/siggate.d.ts +4 -0
- package/dist/siggate.js +90 -0
- package/dist/siggate.js.map +1 -0
- package/dist/site.d.ts +4 -0
- package/dist/site.js +31 -0
- package/dist/site.js.map +1 -1
- package/dist/std.d.ts +1 -0
- package/dist/std.js +129 -0
- package/dist/std.js.map +1 -0
- package/dist/subsume.d.ts +39 -0
- package/dist/subsume.js +573 -0
- package/dist/subsume.js.map +1 -0
- package/dist/trim.d.ts +19 -0
- package/dist/trim.js +155 -0
- package/dist/trim.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +17 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.d.ts +2 -1
- package/dist/unify.js +234 -38
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +8 -1
- package/dist/utility.js +68 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +44 -0
- package/dist/val/AggFuncVal.js +364 -0
- package/dist/val/AggFuncVal.js.map +1 -0
- package/dist/val/ArithFuncVal.d.ts +31 -0
- package/dist/val/ArithFuncVal.js +62 -0
- package/dist/val/ArithFuncVal.js.map +1 -0
- package/dist/val/BagVal.d.ts +7 -0
- package/dist/val/BagVal.js +150 -11
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +9 -1
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.d.ts +1 -1
- package/dist/val/ConjunctVal.js +19 -0
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.d.ts +7 -1
- package/dist/val/ConstraintVal.js +523 -45
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.d.ts +35 -0
- package/dist/val/ContainerKindVal.js +99 -0
- package/dist/val/ContainerKindVal.js.map +1 -0
- package/dist/val/CopyFuncVal.d.ts +1 -2
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.d.ts +1 -0
- package/dist/val/Decimal.js +13 -0
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.d.ts +11 -0
- package/dist/val/DeprecateFuncVal.js +47 -0
- package/dist/val/DeprecateFuncVal.js.map +1 -0
- package/dist/val/DisjunctVal.d.ts +1 -2
- package/dist/val/DisjunctVal.js +269 -53
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.d.ts +15 -0
- package/dist/val/EachFuncVal.js +75 -0
- package/dist/val/EachFuncVal.js.map +1 -0
- package/dist/val/ExpectVal.js +62 -4
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FeatureVal.js +1 -1
- package/dist/val/FeatureVal.js.map +1 -1
- package/dist/val/FilterFuncVal.d.ts +15 -0
- package/dist/val/FilterFuncVal.js +91 -0
- package/dist/val/FilterFuncVal.js.map +1 -0
- package/dist/val/FuncBaseVal.d.ts +7 -1
- package/dist/val/FuncBaseVal.js +183 -2
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.d.ts +39 -0
- package/dist/val/GraphAtomVal.js +184 -0
- package/dist/val/GraphAtomVal.js.map +1 -0
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/JunctionVal.js +24 -1
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.d.ts +1 -1
- package/dist/val/KeyFuncVal.js +38 -30
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +94 -14
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +1 -0
- package/dist/val/MapVal.js +146 -14
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.d.ts +15 -0
- package/dist/val/MatchFuncVal.js +107 -0
- package/dist/val/MatchFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +24 -0
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -1
- package/dist/val/OpBaseVal.js +19 -1
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/OpenFuncVal.js +4 -1
- package/dist/val/OpenFuncVal.js.map +1 -1
- package/dist/val/PackFuncVal.d.ts +15 -0
- package/dist/val/PackFuncVal.js +108 -0
- package/dist/val/PackFuncVal.js.map +1 -0
- package/dist/val/PathFuncVal.d.ts +2 -2
- package/dist/val/PathFuncVal.js +75 -16
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.d.ts +25 -0
- package/dist/val/PathVal.js +150 -0
- package/dist/val/PathVal.js.map +1 -0
- package/dist/val/PlaceVal.d.ts +13 -0
- package/dist/val/PlaceVal.js +131 -0
- package/dist/val/PlaceVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +2 -1
- package/dist/val/PlusOpVal.js +61 -37
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +4 -2
- package/dist/val/PrefVal.js +223 -41
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.d.ts +19 -0
- package/dist/val/RecurseVal.js +217 -0
- package/dist/val/RecurseVal.js.map +1 -0
- package/dist/val/RefVal.d.ts +3 -2
- package/dist/val/RefVal.js +181 -66
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +59 -0
- package/dist/val/ReferFuncVal.js +604 -0
- package/dist/val/ReferFuncVal.js.map +1 -0
- package/dist/val/ScalarKindVal.d.ts +4 -3
- package/dist/val/ScalarKindVal.js +12 -12
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/SuperFuncVal.d.ts +4 -2
- package/dist/val/SuperFuncVal.js +118 -14
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.d.ts +1 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TypeFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +7 -1
- package/dist/val/Val.js +170 -2
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.d.ts +6 -0
- package/dist/val/arith.js +173 -0
- package/dist/val/arith.js.map +1 -0
- package/dist/vet.d.ts +45 -0
- package/dist/vet.js +802 -0
- package/dist/vet.js.map +1 -0
- package/dist/view.d.ts +85 -0
- package/dist/view.js +1948 -0
- package/dist/view.js.map +1 -0
- package/dist/walk.d.ts +2 -0
- package/dist/walk.js +91 -0
- package/dist/walk.js.map +1 -0
- package/grammar/aontu.gbnf +138 -0
- package/grammar/aontu.lark +118 -0
- package/grammar/aontu.tmLanguage.json +184 -0
- package/package.json +30 -8
- package/skill/SKILL.md +37 -0
- package/skill/error-codes.md +62 -0
- package/skill/examples.md +99 -0
- package/skill/grammar-card.md +56 -0
- package/src/agentsmd.ts +135 -0
- package/src/aontu.ts +166 -5
- package/src/cli.ts +3324 -72
- package/src/ctx.ts +93 -1
- package/src/diff.ts +198 -0
- package/src/err.ts +50 -8
- package/src/graph.ts +185 -0
- package/src/hcanon.ts +167 -0
- package/src/hints.ts +291 -8
- package/src/jsonschema.ts +552 -0
- package/src/lang.ts +1049 -110
- package/src/lsp.ts +351 -49
- package/src/mcp-server.ts +187 -0
- package/src/mcp.ts +1130 -0
- package/src/mod-tool.ts +718 -0
- package/src/mod.ts +453 -0
- package/src/patch.ts +628 -0
- package/src/provenance.ts +437 -0
- package/src/query.ts +381 -0
- package/src/reach.ts +213 -0
- package/src/relation.ts +298 -0
- package/src/report-sarif.ts +137 -0
- package/src/sig.ts +345 -0
- package/src/sigdecl.ts +11 -0
- package/src/siggate.ts +144 -0
- package/src/site.ts +36 -1
- package/src/std.ts +131 -0
- package/src/subsume.ts +739 -0
- package/src/trim.ts +195 -0
- package/src/tsconfig.json +10 -4
- package/src/type.ts +51 -2
- package/src/unify.ts +253 -38
- package/src/utility.ts +79 -1
- package/src/val/AggFuncVal.ts +546 -0
- package/src/val/ArithFuncVal.ts +108 -0
- package/src/val/BagVal.ts +158 -12
- package/src/val/CloseFuncVal.ts +9 -1
- package/src/val/ConjunctVal.ts +20 -0
- package/src/val/ConstraintVal.ts +576 -48
- package/src/val/ContainerKindVal.ts +158 -0
- package/src/val/CopyFuncVal.ts +0 -1
- package/src/val/Decimal.ts +15 -0
- package/src/val/DeprecateFuncVal.ts +84 -0
- package/src/val/DisjunctVal.ts +282 -59
- package/src/val/EachFuncVal.ts +133 -0
- package/src/val/ExpectVal.ts +65 -8
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +206 -2
- package/src/val/GraphAtomVal.ts +264 -0
- package/src/val/HideFuncVal.ts +0 -2
- package/src/val/JunctionVal.ts +24 -1
- package/src/val/KeyFuncVal.ts +39 -35
- package/src/val/ListVal.ts +101 -15
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +153 -14
- package/src/val/MatchFuncVal.ts +176 -0
- package/src/val/MoveFuncVal.ts +0 -2
- package/src/val/NilVal.ts +25 -0
- package/src/val/OpBaseVal.ts +20 -1
- package/src/val/OpenFuncVal.ts +4 -2
- package/src/val/PackFuncVal.ts +175 -0
- package/src/val/PathFuncVal.ts +107 -20
- package/src/val/PathVal.ts +221 -0
- package/src/val/PlaceVal.ts +193 -0
- package/src/val/PlusOpVal.ts +67 -39
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +251 -60
- package/src/val/RecurseVal.ts +285 -0
- package/src/val/RefVal.ts +183 -78
- package/src/val/ReferFuncVal.ts +732 -0
- package/src/val/ScalarKindVal.ts +12 -13
- package/src/val/SuperFuncVal.ts +137 -13
- package/src/val/TopVal.ts +1 -2
- package/src/val/TypeFuncVal.ts +0 -2
- package/src/val/UpperFuncVal.ts +0 -1
- package/src/val/Val.ts +216 -4
- package/src/val/VarVal.ts +0 -1
- package/src/val/arith.ts +319 -0
- package/src/vet.ts +1025 -0
- package/src/view.ts +2563 -0
- package/src/walk.ts +99 -0
package/src/val/arith.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// THE ARITHMETIC FAMILY -- add, sub, mul, div, mod, rem.
|
|
5
|
+
//
|
|
6
|
+
// The review's finding I: "Arithmetic stops at `+`", so "prod gets
|
|
7
|
+
// double the replicas" is inexpressible and Kubernetes quantity strings
|
|
8
|
+
// silently CONCATENATE ("500m" + "500m" is "500m500m"). The design
|
|
9
|
+
// pre-registered the semantics these functions must have
|
|
10
|
+
// (docs/capability-review/g8-generation.md, "Arithmetic semantics,
|
|
11
|
+
// pre-registered") and the boundary that keeps `-` `*` `/` `%`
|
|
12
|
+
// reserved: maths arrives as functions or not at all.
|
|
13
|
+
//
|
|
14
|
+
// THE FAMILY IS NUMERIC, WHICH IS WHAT MAKES `add` MORE THAN A SYNONYM
|
|
15
|
+
// FOR `+`. The operator is polymorphic -- concatenation for strings,
|
|
16
|
+
// disjunction for booleans, addition for numbers -- and that is why the
|
|
17
|
+
// quantity strings above concatenate instead of failing. `add("500m",
|
|
18
|
+
// "500m")` is a located error, because a function named for a numeric
|
|
19
|
+
// operation has no business inventing a string. So the two spellings
|
|
20
|
+
// mean different things, and both are kept.
|
|
21
|
+
//
|
|
22
|
+
// Everything else here is the number tower's existing law, applied to
|
|
23
|
+
// five more operations (docs/design/number-model.md):
|
|
24
|
+
//
|
|
25
|
+
// R5 CONTAGION no operation introduces a kind narrower than its
|
|
26
|
+
// operands, so an integer result needs integer
|
|
27
|
+
// operands.
|
|
28
|
+
// D6 EXACT LADDER integer < biginteger < bigdecimal. A mixed exact
|
|
29
|
+
// operation promotes to the WIDEST operand, is
|
|
30
|
+
// computed exactly, and never demotes.
|
|
31
|
+
// FLOAT IS OFF IT binary64 mixed with either big leaf is a hard
|
|
32
|
+
// error in both operand orders, because promotion
|
|
33
|
+
// either way throws away exactness the document
|
|
34
|
+
// asked for by writing `0d`.
|
|
35
|
+
// NO ROUNDING an exact result that will not store is refused,
|
|
36
|
+
// never rounded to fit.
|
|
37
|
+
//
|
|
38
|
+
// and three refusals this file adds, which the pre-registration named:
|
|
39
|
+
//
|
|
40
|
+
// div/mod/rem by ZERO is a hard error in every kind. A ground-truth
|
|
41
|
+
// language has no business manufacturing infinity, and Aontu cannot
|
|
42
|
+
// even write one down -- an overflowing literal is a `not_number`
|
|
43
|
+
// error nil -- so propagating one would invent a value no generated
|
|
44
|
+
// JSON could carry.
|
|
45
|
+
//
|
|
46
|
+
// A NON-FINITE FLOAT RESULT is a located error. This one was already
|
|
47
|
+
// reachable through `+` and reported as neither: `1.0e308+1.0e308`
|
|
48
|
+
// crashed TypeScript with `[aontu/internal]` and leaked Go's raw
|
|
49
|
+
// `json: unsupported value: +Inf` with no code at all (use-cases/
|
|
50
|
+
// BUGS.md 39). PlusOpVal and its Go twin now go through the same
|
|
51
|
+
// check.
|
|
52
|
+
//
|
|
53
|
+
// DIVISION IS NOT CLOSED OVER THE DECIMAL LEAF, so div/mod/rem refuse
|
|
54
|
+
// a bigdecimal operand rather than rounding one third to fit. See
|
|
55
|
+
// `inexact_divide`'s hint: scale to integers, which is the money wire
|
|
56
|
+
// convention anyway, or accept a float.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
import type { Val } from '../type'
|
|
60
|
+
|
|
61
|
+
import { AontuContext } from '../ctx'
|
|
62
|
+
import { makeNilErr } from '../err'
|
|
63
|
+
|
|
64
|
+
import { IntegerVal } from './IntegerVal'
|
|
65
|
+
import { NumberVal } from './NumberVal'
|
|
66
|
+
import { BigIntegerVal } from './BigIntegerVal'
|
|
67
|
+
import { BigDecimalVal } from './BigDecimalVal'
|
|
68
|
+
import { Decimal, decimalOverBudget } from './Decimal'
|
|
69
|
+
import { isIntegerStorable } from './numkind'
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
type ArithOp = 'add' | 'sub' | 'mul' | 'div' | 'mod' | 'rem'
|
|
73
|
+
|
|
74
|
+
// The three that divide, and therefore the three that can be handed a
|
|
75
|
+
// zero divisor and cannot answer over the decimal leaf.
|
|
76
|
+
function divides(op: ArithOp): boolean {
|
|
77
|
+
return 'div' === op || 'mod' === op || 'rem' === op
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// The numeric leaves, told apart by their own flags rather than by the
|
|
82
|
+
// JavaScript type of the peg: `integer` and `float` share `number`.
|
|
83
|
+
type ArithKind = 'integer' | 'float' | 'biginteger' | 'bigdecimal'
|
|
84
|
+
|
|
85
|
+
const EXACT_RANK: Record<string, number> = {
|
|
86
|
+
integer: 1,
|
|
87
|
+
biginteger: 2,
|
|
88
|
+
bigdecimal: 3,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
function isBig(k: ArithKind): boolean {
|
|
93
|
+
return 'biginteger' === k || 'bigdecimal' === k
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
// A pref operand contributes its preferred value, and therefore that
|
|
98
|
+
// value's kind too -- the same rule `+` applies.
|
|
99
|
+
function unpref(v: any): any {
|
|
100
|
+
while (v?.isPref) {
|
|
101
|
+
v = v.peg
|
|
102
|
+
}
|
|
103
|
+
return v
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
function arithKind(v: any): ArithKind | undefined {
|
|
108
|
+
// Every caller hands a driven Val (an operand past the signature
|
|
109
|
+
// gate, or a bag member from the aggregate fold), so scalarhood is
|
|
110
|
+
// the one question -- a container member lands here.
|
|
111
|
+
if (true !== v?.isScalar) {
|
|
112
|
+
return undefined
|
|
113
|
+
}
|
|
114
|
+
if (v.isBigInteger) {
|
|
115
|
+
return 'biginteger'
|
|
116
|
+
}
|
|
117
|
+
if (v.isBigDecimal) {
|
|
118
|
+
return 'bigdecimal'
|
|
119
|
+
}
|
|
120
|
+
if (v.isInteger) {
|
|
121
|
+
return 'integer'
|
|
122
|
+
}
|
|
123
|
+
return 'number' === typeof v.peg ? 'float' : undefined
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
// An exact-ladder operand as an exact integer. Only reached for the two
|
|
128
|
+
// integral leaves; an `integer` peg is integral by construction.
|
|
129
|
+
function asInteger(v: any, k: ArithKind): bigint {
|
|
130
|
+
return 'biginteger' === k ? v.peg : BigInt(v.peg)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
function asDecimal(v: any, k: ArithKind): Decimal {
|
|
135
|
+
return 'bigdecimal' === k ? v.peg : new Decimal(asInteger(v, k), 0)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// The whole family, in one function, because every rule above is a rule
|
|
140
|
+
// about ARITHMETIC and not about any one operation. `node` is the value
|
|
141
|
+
// the error is located at -- the call, or the `+` op.
|
|
142
|
+
// `attempt` is the name the ERROR reports, which is the operation
|
|
143
|
+
// except when a fold borrows one: `sum` adds, but a bad member is the
|
|
144
|
+
// author's `sum` call and must say so.
|
|
145
|
+
function arith(
|
|
146
|
+
ctx: AontuContext | undefined,
|
|
147
|
+
op: ArithOp,
|
|
148
|
+
node: Val,
|
|
149
|
+
a: Val,
|
|
150
|
+
b: Val,
|
|
151
|
+
attempt?: string
|
|
152
|
+
): Val {
|
|
153
|
+
const name = attempt ?? op
|
|
154
|
+
const av: any = unpref(a)
|
|
155
|
+
const bv: any = unpref(b)
|
|
156
|
+
const ak = arithKind(av)
|
|
157
|
+
const bk = arithKind(bv)
|
|
158
|
+
|
|
159
|
+
// A non-numeric operand is not something to wait for: `resolve` is
|
|
160
|
+
// only reached once every argument has settled, so a kind, a map, a
|
|
161
|
+
// string or a boolean here is the author's mistake and is named as
|
|
162
|
+
// one. (`+` differs, and must: it has answers for strings and
|
|
163
|
+
// booleans.)
|
|
164
|
+
if (undefined === ak || undefined === bk) {
|
|
165
|
+
return makeNilErr(ctx, 'invalid-arg', node, undefined, name)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// A big leaf never silently becomes a binary float, in EITHER operand
|
|
169
|
+
// order. The error names both leaves in operand order.
|
|
170
|
+
if (('float' === ak && isBig(bk)) || (isBig(ak) && 'float' === bk)) {
|
|
171
|
+
return makeNilErr(ctx, 'exact_float_mix', node, undefined, name,
|
|
172
|
+
{ left: ak, right: bk })
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if ('float' === ak || 'float' === bk) {
|
|
176
|
+
return floatArith(ctx, op, name, node, av.peg, bv.peg)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const rank = EXACT_RANK[bk] < EXACT_RANK[ak] ? EXACT_RANK[ak] : EXACT_RANK[bk]
|
|
180
|
+
|
|
181
|
+
if (EXACT_RANK.bigdecimal === rank) {
|
|
182
|
+
return decimalArith(ctx, op, name, node, asDecimal(av, ak), asDecimal(bv, bk))
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return integerArith(ctx, op, name, node, asInteger(av, ak),
|
|
186
|
+
asInteger(bv, bk), EXACT_RANK.biginteger === rank)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
// IEEE-754 binary64, with the JSON-superset constraint still biting: an
|
|
191
|
+
// infinite or NaN result is a located error rather than a value, because
|
|
192
|
+
// there is no way to write one down and no JSON that could carry it.
|
|
193
|
+
function floatArith(
|
|
194
|
+
ctx: AontuContext | undefined,
|
|
195
|
+
op: ArithOp,
|
|
196
|
+
name: string,
|
|
197
|
+
node: Val,
|
|
198
|
+
x: number,
|
|
199
|
+
y: number
|
|
200
|
+
): Val {
|
|
201
|
+
if (divides(op) && 0 === y) {
|
|
202
|
+
return makeNilErr(ctx, 'divide_by_zero', node, undefined, name)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const out =
|
|
206
|
+
'add' === op ? x + y :
|
|
207
|
+
'sub' === op ? x - y :
|
|
208
|
+
'mul' === op ? x * y :
|
|
209
|
+
'div' === op ? x / y :
|
|
210
|
+
// Truncated remainder, sign following the DIVIDEND, which is
|
|
211
|
+
// what JavaScript's `%` and Go's math.Mod both give...
|
|
212
|
+
'rem' === op ? x % y :
|
|
213
|
+
// ...and the floored modulus, sign following the DIVISOR,
|
|
214
|
+
// built from it. Adding the divisor back moves a remainder
|
|
215
|
+
// whose sign disagrees into agreement, and leaves an exact
|
|
216
|
+
// zero alone.
|
|
217
|
+
flooredMod(x % y, y)
|
|
218
|
+
|
|
219
|
+
return Number.isFinite(out) ?
|
|
220
|
+
new NumberVal({ peg: out }) :
|
|
221
|
+
makeNilErr(ctx, 'float_overflow', node, undefined, name)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
function flooredMod(rem: number, y: number): number {
|
|
226
|
+
return 0 !== rem && (rem < 0) !== (y < 0) ? rem + y : rem
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
// The exact integral leaves. Both compute in bigint, so nothing passes
|
|
231
|
+
// through binary64 and nothing rounds; only the storage test at the end
|
|
232
|
+
// differs, because `biginteger` is unbounded and `integer` is not.
|
|
233
|
+
function integerArith(
|
|
234
|
+
ctx: AontuContext | undefined,
|
|
235
|
+
op: ArithOp,
|
|
236
|
+
name: string,
|
|
237
|
+
node: Val,
|
|
238
|
+
x: bigint,
|
|
239
|
+
y: bigint,
|
|
240
|
+
big: boolean
|
|
241
|
+
): Val {
|
|
242
|
+
if (divides(op) && 0n === y) {
|
|
243
|
+
return makeNilErr(ctx, 'divide_by_zero', node, undefined, name)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const out =
|
|
247
|
+
'add' === op ? x + y :
|
|
248
|
+
'sub' === op ? x - y :
|
|
249
|
+
'mul' === op ? x * y :
|
|
250
|
+
// TRUNCATION TOWARD ZERO, stated once here rather than left to
|
|
251
|
+
// whichever host `/` each port happens to call: div(-7, 2) is
|
|
252
|
+
// -3, not -4. BigInt division truncates, and so does Go's
|
|
253
|
+
// big.Int.Quo (its Div floors, which is why the Go twin must
|
|
254
|
+
// not use it).
|
|
255
|
+
'div' === op ? x / y :
|
|
256
|
+
'rem' === op ? x % y :
|
|
257
|
+
flooredModBig(x % y, y)
|
|
258
|
+
|
|
259
|
+
if (big) {
|
|
260
|
+
// Unbounded and exact: nothing to check, and no demotion to
|
|
261
|
+
// `integer` however small the result.
|
|
262
|
+
return new BigIntegerVal({ peg: out })
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// The result faces the SAME storage contract R1 puts on a literal --
|
|
266
|
+
// integral, inside the int64 window, and exactly representable in
|
|
267
|
+
// binary64 -- because Go's int64 holds results TypeScript's double
|
|
268
|
+
// cannot, and without a shared test a document would resolve in one
|
|
269
|
+
// port and round in the other.
|
|
270
|
+
return isIntegerStorable(out) ?
|
|
271
|
+
new IntegerVal({ peg: Number(out) }) :
|
|
272
|
+
makeNilErr(ctx, 'inexact_integer_sum', node, undefined, name,
|
|
273
|
+
{ sum: out.toString() })
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
function flooredModBig(rem: bigint, y: bigint): bigint {
|
|
278
|
+
return 0n !== rem && (rem < 0n) !== (y < 0n) ? rem + y : rem
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
// The decimal leaf. Addition, subtraction and multiplication are exact
|
|
283
|
+
// coefficient arithmetic and land here; division does not, and says so.
|
|
284
|
+
function decimalArith(
|
|
285
|
+
ctx: AontuContext | undefined,
|
|
286
|
+
op: ArithOp,
|
|
287
|
+
name: string,
|
|
288
|
+
node: Val,
|
|
289
|
+
x: Decimal,
|
|
290
|
+
y: Decimal
|
|
291
|
+
): Val {
|
|
292
|
+
if (divides(op)) {
|
|
293
|
+
// EXACT DECIMAL DIVISION IS NOT CLOSED: one third has no finite
|
|
294
|
+
// decimal form, so a `div` over this leaf either rounds -- the one
|
|
295
|
+
// thing the leaf exists to refuse -- or refuses. It refuses, and the
|
|
296
|
+
// hint names both ways out.
|
|
297
|
+
return makeNilErr(ctx, 'inexact_divide', node, undefined, name)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const out =
|
|
301
|
+
'add' === op ? x.add(y) :
|
|
302
|
+
'sub' === op ? x.add(y.negate()) :
|
|
303
|
+
x.multiply(y)
|
|
304
|
+
|
|
305
|
+
// The budget applies to RESULTS as well as literals: an exact answer
|
|
306
|
+
// too wide to hold is refused, never rounded to fit.
|
|
307
|
+
return decimalOverBudget(out) ?
|
|
308
|
+
makeNilErr(ctx, 'decimal_budget', node, undefined, name) :
|
|
309
|
+
new BigDecimalVal({ peg: out })
|
|
310
|
+
} /* node:coverage ignore next 9 */
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
export type {
|
|
314
|
+
ArithOp,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export {
|
|
318
|
+
arith,
|
|
319
|
+
}
|