@aster-cloud/aster-lang-ts 1.0.6 → 1.0.9
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/dist/src/ast/ast.d.ts +1 -0
- package/dist/src/ast/ast.d.ts.map +1 -1
- package/dist/src/ast/ast.js +1 -0
- package/dist/src/ast/ast.js.map +1 -1
- package/dist/src/config/lexicons/de-DE.d.ts.map +1 -1
- package/dist/src/config/lexicons/de-DE.js +1 -0
- package/dist/src/config/lexicons/de-DE.js.map +1 -1
- package/dist/src/config/lexicons/en-US.d.ts.map +1 -1
- package/dist/src/config/lexicons/en-US.js +1 -0
- package/dist/src/config/lexicons/en-US.js.map +1 -1
- package/dist/src/config/lexicons/hi-IN.d.ts.map +1 -1
- package/dist/src/config/lexicons/hi-IN.js +1 -0
- package/dist/src/config/lexicons/hi-IN.js.map +1 -1
- package/dist/src/config/lexicons/template.d.ts.map +1 -1
- package/dist/src/config/lexicons/template.js +1 -0
- package/dist/src/config/lexicons/template.js.map +1 -1
- package/dist/src/config/lexicons/zh-CN.d.ts.map +1 -1
- package/dist/src/config/lexicons/zh-CN.js +1 -0
- package/dist/src/config/lexicons/zh-CN.js.map +1 -1
- package/dist/src/config/semantic.d.ts +1 -0
- package/dist/src/config/semantic.d.ts.map +1 -1
- package/dist/src/config/semantic.js +1 -0
- package/dist/src/config/semantic.js.map +1 -1
- package/dist/src/config/token-kind.d.ts +3 -0
- package/dist/src/config/token-kind.d.ts.map +1 -1
- package/dist/src/config/token-kind.js +3 -0
- package/dist/src/config/token-kind.js.map +1 -1
- package/dist/src/core/core_ir.d.ts +1 -0
- package/dist/src/core/core_ir.d.ts.map +1 -1
- package/dist/src/core/core_ir.js +1 -0
- package/dist/src/core/core_ir.js.map +1 -1
- package/dist/src/core/interpreter.d.ts.map +1 -1
- package/dist/src/core/interpreter.js +161 -0
- package/dist/src/core/interpreter.js.map +1 -1
- package/dist/src/core/pretty_core.d.ts.map +1 -1
- package/dist/src/core/pretty_core.js +1 -0
- package/dist/src/core/pretty_core.js.map +1 -1
- package/dist/src/core/visitor.d.ts.map +1 -1
- package/dist/src/core/visitor.js +1 -0
- package/dist/src/core/visitor.js.map +1 -1
- package/dist/src/diagnostics/diagnostics.d.ts +2 -0
- package/dist/src/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/src/diagnostics/diagnostics.js +6 -0
- package/dist/src/diagnostics/diagnostics.js.map +1 -1
- package/dist/src/diagnostics/error_codes.d.ts +1 -0
- package/dist/src/diagnostics/error_codes.d.ts.map +1 -1
- package/dist/src/diagnostics/error_codes.js +2 -0
- package/dist/src/diagnostics/error_codes.js.map +1 -1
- package/dist/src/frontend/lexer.d.ts +7 -0
- package/dist/src/frontend/lexer.d.ts.map +1 -1
- package/dist/src/frontend/lexer.js +37 -2
- package/dist/src/frontend/lexer.js.map +1 -1
- package/dist/src/lower_to_core.js +2 -0
- package/dist/src/lower_to_core.js.map +1 -1
- package/dist/src/parser/expr-stmt-parser.d.ts.map +1 -1
- package/dist/src/parser/expr-stmt-parser.js +219 -41
- package/dist/src/parser/expr-stmt-parser.js.map +1 -1
- package/dist/src/typecheck/expression.d.ts.map +1 -1
- package/dist/src/typecheck/expression.js +55 -0
- package/dist/src/typecheck/expression.js.map +1 -1
- package/dist/src/typecheck/type_system.d.ts.map +1 -1
- package/dist/src/typecheck/type_system.js +9 -1
- package/dist/src/typecheck/type_system.js.map +1 -1
- package/dist/src/types/base.d.ts +10 -0
- package/dist/src/types/base.d.ts.map +1 -1
- package/dist/src/types.d.ts +10 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +1 -0
- package/dist/src/types.js.map +1 -1
- package/dist/test/unit/alias-poem-story.test.d.ts +2 -0
- package/dist/test/unit/alias-poem-story.test.d.ts.map +1 -0
- package/dist/test/unit/alias-poem-story.test.js +106 -0
- package/dist/test/unit/alias-poem-story.test.js.map +1 -0
- package/dist/test/unit/apply-call.test.d.ts +2 -0
- package/dist/test/unit/apply-call.test.d.ts.map +1 -0
- package/dist/test/unit/apply-call.test.js +79 -0
- package/dist/test/unit/apply-call.test.js.map +1 -0
- package/dist/test/unit/date-builtins.test.d.ts +2 -0
- package/dist/test/unit/date-builtins.test.d.ts.map +1 -0
- package/dist/test/unit/date-builtins.test.js +74 -0
- package/dist/test/unit/date-builtins.test.js.map +1 -0
- package/dist/test/unit/decimal-literals.test.d.ts +2 -0
- package/dist/test/unit/decimal-literals.test.d.ts.map +1 -0
- package/dist/test/unit/decimal-literals.test.js +76 -0
- package/dist/test/unit/decimal-literals.test.js.map +1 -0
- package/dist/test/unit/decimal-mixing-typecheck.test.d.ts +2 -0
- package/dist/test/unit/decimal-mixing-typecheck.test.d.ts.map +1 -0
- package/dist/test/unit/decimal-mixing-typecheck.test.js +80 -0
- package/dist/test/unit/decimal-mixing-typecheck.test.js.map +1 -0
- package/dist/test/unit/decimal-round-divide.test.d.ts +2 -0
- package/dist/test/unit/decimal-round-divide.test.d.ts.map +1 -0
- package/dist/test/unit/decimal-round-divide.test.js +53 -0
- package/dist/test/unit/decimal-round-divide.test.js.map +1 -0
- package/dist/test/unit/multiline-continuation.test.d.ts +2 -0
- package/dist/test/unit/multiline-continuation.test.d.ts.map +1 -0
- package/dist/test/unit/multiline-continuation.test.js +87 -0
- package/dist/test/unit/multiline-continuation.test.js.map +1 -0
- package/dist/test/unit/tides-ballad.test.d.ts +2 -0
- package/dist/test/unit/tides-ballad.test.d.ts.map +1 -0
- package/dist/test/unit/tides-ballad.test.js +80 -0
- package/dist/test/unit/tides-ballad.test.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { compile } from '../../src/browser.js';
|
|
4
|
+
import { evaluate } from '../../src/core/interpreter.js';
|
|
5
|
+
// Date.* 合规原语(Stable v1):epoch-day Int + 纯整数 proleptic Gregorian + 禁 today()。
|
|
6
|
+
// fixture 取自 Codex 设计清单(session 019f12c6),双引擎须逐位一致(同 fixture 进 truffle)。
|
|
7
|
+
function run(body) {
|
|
8
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
9
|
+
assert.ok(c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
10
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
11
|
+
assert.ok(ev.success, `eval: ${ev.error ?? ''}`);
|
|
12
|
+
return ev.value;
|
|
13
|
+
}
|
|
14
|
+
const RI = (expr) => `Rule main given seed as Int, produce Int:\n Return ${expr}.`;
|
|
15
|
+
function evalErr(body) {
|
|
16
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
17
|
+
assert.ok(c.core);
|
|
18
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
19
|
+
return ev.success ? '<no error>' : String(ev.error);
|
|
20
|
+
}
|
|
21
|
+
describe('Date.* builtin — fromISO (epoch-day)', () => {
|
|
22
|
+
it('1970-01-01 == 0', () => assert.equal(run(RI('Date.fromISO("1970-01-01")')), 0));
|
|
23
|
+
it('1970-01-02 == 1', () => assert.equal(run(RI('Date.fromISO("1970-01-02")')), 1));
|
|
24
|
+
it('1969-12-31 == -1', () => assert.equal(run(RI('Date.fromISO("1969-12-31")')), -1));
|
|
25
|
+
it('2026-06-29 == 20633', () => assert.equal(run(RI('Date.fromISO("2026-06-29")')), 20633));
|
|
26
|
+
it('2000-02-29 == 11016', () => assert.equal(run(RI('Date.fromISO("2000-02-29")')), 11016));
|
|
27
|
+
it('0001-01-01 == -719162', () => assert.equal(run(RI('Date.fromISO("0001-01-01")')), -719162));
|
|
28
|
+
it('9999-12-31 == 2932896', () => assert.equal(run(RI('Date.fromISO("9999-12-31")')), 2932896));
|
|
29
|
+
});
|
|
30
|
+
describe('Date.* builtin — leap year validation', () => {
|
|
31
|
+
it('2000-02-29 ok', () => assert.equal(run(RI('Date.day(Date.fromISO("2000-02-29"))')), 29));
|
|
32
|
+
it('2400-02-29 ok', () => assert.equal(run(RI('Date.day(Date.fromISO("2400-02-29"))')), 29));
|
|
33
|
+
it('2024-02-29 ok', () => assert.equal(run(RI('Date.day(Date.fromISO("2024-02-29"))')), 29));
|
|
34
|
+
it('1900-02-29 errors (÷100 非闰)', () => assert.match(evalErr(RI('Date.fromISO("1900-02-29")')), /Date\.InvalidISODate/));
|
|
35
|
+
it('2100-02-29 errors', () => assert.match(evalErr(RI('Date.fromISO("2100-02-29")')), /Date\.InvalidISODate/));
|
|
36
|
+
it('2023-02-29 errors', () => assert.match(evalErr(RI('Date.fromISO("2023-02-29")')), /Date\.InvalidISODate/));
|
|
37
|
+
});
|
|
38
|
+
describe('Date.* builtin — daysBetween / addDays', () => {
|
|
39
|
+
it('same day == 0', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("1970-01-01"), Date.fromISO("1970-01-01"))')), 0));
|
|
40
|
+
it('1 day forward', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("1970-01-01"), Date.fromISO("1970-01-02"))')), 1));
|
|
41
|
+
it('1 day backward (negative)', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("1970-01-02"), Date.fromISO("1970-01-01"))')), -1));
|
|
42
|
+
it('leap-year span 2024-02-28→03-01 == 2', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("2024-02-28"), Date.fromISO("2024-03-01"))')), 2));
|
|
43
|
+
it('non-leap span 2023-02-28→03-01 == 1', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("2023-02-28"), Date.fromISO("2023-03-01"))')), 1));
|
|
44
|
+
it('addDays +30', () => assert.equal(run(RI('Date.daysBetween(Date.fromISO("1970-01-01"), Date.addDays(Date.fromISO("1970-01-01"), 30))')), 30));
|
|
45
|
+
it('addDays crosses leap day 2024-02-28 +1 == 02-29', () => assert.equal(run(RI('Date.day(Date.addDays(Date.fromISO("2024-02-28"), 1))')), 29));
|
|
46
|
+
});
|
|
47
|
+
describe('Date.* builtin — year/month/day extractors', () => {
|
|
48
|
+
it('year', () => assert.equal(run(RI('Date.year(Date.fromISO("2026-06-29"))')), 2026));
|
|
49
|
+
it('month', () => assert.equal(run(RI('Date.month(Date.fromISO("2026-06-29"))')), 6));
|
|
50
|
+
it('day', () => assert.equal(run(RI('Date.day(Date.fromISO("2026-06-29"))')), 29));
|
|
51
|
+
it('year 0001-01-01 == 1', () => assert.equal(run(RI('Date.year(Date.fromISO("0001-01-01"))')), 1));
|
|
52
|
+
it('month 9999-12-31 == 12', () => assert.equal(run(RI('Date.month(Date.fromISO("9999-12-31"))')), 12));
|
|
53
|
+
});
|
|
54
|
+
describe('Date.* builtin — strict format rejection', () => {
|
|
55
|
+
for (const bad of ['', '2026-2-03', '2026-02-3', '2026-02-30', '2026-13-01', '2026-00-01', '2026-01-00',
|
|
56
|
+
' 2026-01-01', '2026-01-01 ', '2026-01-01T00:00:00Z', '0000-01-01', '10000-01-01']) {
|
|
57
|
+
it(`rejects ${JSON.stringify(bad)}`, () => assert.match(evalErr(RI(`Date.fromISO(${JSON.stringify(bad)})`)), /Date\.InvalidISODate/));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
describe('Date.* builtin — 合规业务场景 (评估日期作输入)', () => {
|
|
61
|
+
// "申请日期距评估日期 ≥ 30 天" — 用 epoch-day Int 直接比较,无需 isBefore builtin。
|
|
62
|
+
const consentRule = `Rule main given seed as Int, produce Bool:
|
|
63
|
+
Let evalDay be Date.fromISO("2026-06-29").
|
|
64
|
+
Let consentDay be Date.fromISO("2026-05-30").
|
|
65
|
+
Return Date.daysBetween(consentDay, evalDay) at least 30.`;
|
|
66
|
+
it('consent 30 days ago → at least 30 = true', () => {
|
|
67
|
+
const c = compile(`Module probe.\n${consentRule}\n`);
|
|
68
|
+
assert.ok(c.core);
|
|
69
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
70
|
+
assert.ok(ev.success, ev.error ?? '');
|
|
71
|
+
assert.equal(ev.value, true);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=date-builtins.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-builtins.test.js","sourceRoot":"","sources":["../../../test/unit/date-builtins.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-literals.test.d.ts","sourceRoot":"","sources":["../../../test/unit/decimal-literals.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { compile } from '../../src/browser.js';
|
|
4
|
+
import { evaluate } from '../../src/core/interpreter.js';
|
|
5
|
+
// Decimal M1(ADR 0025):m 后缀字面量 + canonical 字符串 + 精确加减乘 + 比较 + 禁 Double 混算。
|
|
6
|
+
// 运行时 Decimal 值=decimal.js 实例;测试比规范化字符串(与 truffle BigDecimal toPlainString 对齐)。
|
|
7
|
+
function runDecimal(body) {
|
|
8
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
9
|
+
assert.ok(c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
10
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
11
|
+
assert.ok(ev.success, `eval: ${ev.error ?? ''}`);
|
|
12
|
+
return ev.value.toFixed();
|
|
13
|
+
}
|
|
14
|
+
function runBool(body) {
|
|
15
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
16
|
+
assert.ok(c.core);
|
|
17
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
18
|
+
assert.ok(ev.success, ev.error ?? '');
|
|
19
|
+
return ev.value;
|
|
20
|
+
}
|
|
21
|
+
function evalErr(body) {
|
|
22
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
23
|
+
if (!c.core)
|
|
24
|
+
return 'COMPILE:' + JSON.stringify(c.parseErrors ?? []);
|
|
25
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
26
|
+
return ev.success ? '<no error>' : String(ev.error);
|
|
27
|
+
}
|
|
28
|
+
const RD = (expr) => `Rule main given seed as Int, produce Decimal:\n Return ${expr}.`;
|
|
29
|
+
const RB = (expr) => `Rule main given seed as Int, produce Bool:\n Return ${expr}.`;
|
|
30
|
+
describe('Decimal M1 — 字面量位数上限 (ADR 0025 v1 ≤38, Codex P1)', () => {
|
|
31
|
+
// 超 38 位会让 decimal.js(precision 80) 乘法静默舍入 vs BigDecimal 精确 → 双引擎分歧。硬拒。
|
|
32
|
+
it('38 位有效数字 → 接受', () => assert.equal(runDecimal(RD('1'.repeat(38) + 'm')), '1'.repeat(38)));
|
|
33
|
+
it('39 位有效数字 → 拒绝 (parse error)', () => assert.match(evalErr(RD('1'.repeat(39) + 'm')), /COMPILE|38|significant digits/i));
|
|
34
|
+
it('纯小数前导零不计有效位 (0.000…1 仅 1 位)', () => assert.equal(runDecimal(RD('0.' + '0'.repeat(38) + '1m')), '0.' + '0'.repeat(38) + '1'));
|
|
35
|
+
});
|
|
36
|
+
describe('Decimal M1 — 字面量 canonical', () => {
|
|
37
|
+
it('1.08m → 1.08', () => assert.equal(runDecimal(RD('1.08m')), '1.08'));
|
|
38
|
+
it('1.00m → 1 (去尾零)', () => assert.equal(runDecimal(RD('1.00m')), '1'));
|
|
39
|
+
it('001.2300m → 1.23 (去前导+尾零)', () => assert.equal(runDecimal(RD('001.2300m')), '1.23'));
|
|
40
|
+
it('0.000m → 0', () => assert.equal(runDecimal(RD('0.000m')), '0'));
|
|
41
|
+
it('10m → 10', () => assert.equal(runDecimal(RD('10m')), '10'));
|
|
42
|
+
});
|
|
43
|
+
describe('Decimal M1 — 精确加减乘', () => {
|
|
44
|
+
it('0.1m plus 0.2m → 0.3 (无二进制误差)', () => assert.equal(runDecimal(RD('0.1m plus 0.2m')), '0.3'));
|
|
45
|
+
it('100.01m minus 0.02m → 99.99', () => assert.equal(runDecimal(RD('100.01m minus 0.02m')), '99.99'));
|
|
46
|
+
it('1.20m times 1.080m → 1.296 (scale 增长)', () => assert.equal(runDecimal(RD('1.20m times 1.080m')), '1.296'));
|
|
47
|
+
it('price times taxRate 自然写法', () => assert.equal(runDecimal(RD('100.00m times 1.08m')), '108'));
|
|
48
|
+
});
|
|
49
|
+
describe('Decimal M1 — Int/Long 精确提升', () => {
|
|
50
|
+
it('1m plus 2 (Int) → 3', () => assert.equal(runDecimal(RD('1m plus 2')), '3'));
|
|
51
|
+
it('5 (Int) times 1.5m → 7.5', () => assert.equal(runDecimal(RD('5 times 1.5m')), '7.5'));
|
|
52
|
+
});
|
|
53
|
+
describe('Decimal M1 — 比较 (compareTo, 值语义)', () => {
|
|
54
|
+
it('1.0m equals to 1.00m → true (值语义)', () => assert.equal(runBool(RB('1.0m equals to 1.00m')), true));
|
|
55
|
+
it('1.01m greater than 1.001m → true', () => assert.equal(runBool(RB('1.01m greater than 1.001m')), true));
|
|
56
|
+
it('100.00m at least 50m → true', () => assert.equal(runBool(RB('100.00m at least 50m')), true));
|
|
57
|
+
it('0.1m plus 0.2m equals to 0.3m → true (精确)', () => assert.equal(runBool(RB('0.1m plus 0.2m equals to 0.3m')), true));
|
|
58
|
+
});
|
|
59
|
+
describe('Decimal M1 — 禁 Double 混算 (runtime 层: 非整数 Double 可catch)', () => {
|
|
60
|
+
// 注:runtime Int/Double 都是 JS number, 无法区分 2.0(Double) vs 2(Int)——非整数 Double
|
|
61
|
+
// (2.5)runtime 能 catch; 整数值 Double(2.0)的混算禁须由 **typechecker** 在编译期拦
|
|
62
|
+
// (AST 节点 kind Int/Double/Decimal 可分)。typechecker 规则是 M1 后续(见 ADR 0025)。
|
|
63
|
+
it('1.08m plus 2.5 (非整数 Double) → error', () => assert.match(evalErr(RD('1.08m plus 2.5')), /Cannot combine Decimal and Double/));
|
|
64
|
+
it('2.5 (Double) times 3m → error', () => assert.match(evalErr(RD('2.5 times 3m')), /Cannot combine Decimal and Double/));
|
|
65
|
+
it('Decimal / 禁 → error', () => assert.match(evalErr(RD('6m divided by 2m')), /Decimal .* not supported|use Decimal\.divide/i));
|
|
66
|
+
});
|
|
67
|
+
describe('Decimal M1 — 合规场景 (信贷 DTI 用 Decimal)', () => {
|
|
68
|
+
it('月负债+预估还款 精确', () => {
|
|
69
|
+
const src = `Rule main given seed as Int, produce Decimal:
|
|
70
|
+
Let debt be 1200.50m.
|
|
71
|
+
Let payment be 800.25m.
|
|
72
|
+
Return debt plus payment.`;
|
|
73
|
+
assert.equal(runDecimal(src), '2000.75');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=decimal-literals.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-literals.test.js","sourceRoot":"","sources":["../../../test/unit/decimal-literals.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-mixing-typecheck.test.d.ts","sourceRoot":"","sources":["../../../test/unit/decimal-mixing-typecheck.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { canonicalize } from '../../src/frontend/canonicalizer.js';
|
|
4
|
+
import { lex } from '../../src/frontend/lexer.js';
|
|
5
|
+
import { parse } from '../../src/parser.js';
|
|
6
|
+
import { lowerModule } from '../../src/lower_to_core.js';
|
|
7
|
+
import { typecheckModule } from '../../src/typecheck.js';
|
|
8
|
+
// Decimal↔Double 混算编译期拦截(ADR 0025,M1 后续)。
|
|
9
|
+
// runtime 只能 catch 非整数 Double(2.5);整数值 Double(2.0)与 Int(2)在 JS number
|
|
10
|
+
// 不可分——必须靠 typechecker 在编译期按 AST 节点 kind(Double vs Decimal)拦截。
|
|
11
|
+
// Int/Long↔Decimal 精确提升放行。错误码 E031 DECIMAL_DOUBLE_MIXING。
|
|
12
|
+
function diagnose(body) {
|
|
13
|
+
const src = `Module probe.\n${body}\n`;
|
|
14
|
+
const ast = parse(lex(canonicalize(src))).ast;
|
|
15
|
+
const core = lowerModule(ast);
|
|
16
|
+
return typecheckModule(core).map(d => `${d.code}:${d.message}`);
|
|
17
|
+
}
|
|
18
|
+
function hasMixingError(body) {
|
|
19
|
+
return diagnose(body).some(d => d.startsWith('E031'));
|
|
20
|
+
}
|
|
21
|
+
describe('Decimal M1 后续 — Double↔Decimal 混算编译期拦截', () => {
|
|
22
|
+
it('1.08m plus 2.0 (整数值 Double) → E031 (runtime 抓不到, 编译期拦)', () => {
|
|
23
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return 1.08m plus 2.0.'));
|
|
24
|
+
});
|
|
25
|
+
it('2.0 (Double) times 3m → E031', () => {
|
|
26
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return 2.0 times 3m.'));
|
|
27
|
+
});
|
|
28
|
+
it('1.08m minus 2.5 (非整数 Double) → E031 (编译期也拦, 不止 runtime)', () => {
|
|
29
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return 1.08m minus 2.5.'));
|
|
30
|
+
});
|
|
31
|
+
it('嵌套: (100.00m times 1.08m) plus 0.5 → E031 (Decimal 结果类型传播)', () => {
|
|
32
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return 100.00m times 1.08m plus 0.5.'));
|
|
33
|
+
});
|
|
34
|
+
// Codex 审查 P0:比较运算符混算(整数值 Double 不可 runtime catch,必须编译期拦)
|
|
35
|
+
it('1.0m equals to 1.0 (整数值 Double 比较) → E031 (TS runtime=true 但 Truffle 抛错=分歧)', () => {
|
|
36
|
+
assert.ok(hasMixingError('Rule main produce Bool:\n Return 1.0m equals to 1.0.'));
|
|
37
|
+
});
|
|
38
|
+
it('1.0m at most 2.0 → E031', () => {
|
|
39
|
+
assert.ok(hasMixingError('Rule main produce Bool:\n Return 1.0m at most 2.0.'));
|
|
40
|
+
});
|
|
41
|
+
it('2.0 greater than 1.0m → E031', () => {
|
|
42
|
+
assert.ok(hasMixingError('Rule main produce Bool:\n Return 2.0 greater than 1.0m.'));
|
|
43
|
+
});
|
|
44
|
+
// Codex 审查 P0:Decimal.round/divide 的 Decimal 参数位混 Double
|
|
45
|
+
it('Decimal.divide(1m, 2.0, 2, "HALF_UP") → E031 (divisor 是 Double)', () => {
|
|
46
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return Decimal.divide(1m, 2.0, 2, "HALF_UP").'));
|
|
47
|
+
});
|
|
48
|
+
it('Decimal.round(2.0, 1, "HALF_UP") → E031 (x 是 Double)', () => {
|
|
49
|
+
assert.ok(hasMixingError('Rule main produce Decimal:\n Return Decimal.round(2.0, 1, "HALF_UP").'));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('Decimal M1 后续 — 比较/builtin 合法组合不误报', () => {
|
|
53
|
+
it('1.0m equals to 1.00m (Decimal 比较) → 无 E031', () => {
|
|
54
|
+
assert.ok(!hasMixingError('Rule main produce Bool:\n Return 1.0m equals to 1.00m.'));
|
|
55
|
+
});
|
|
56
|
+
it('1.0m at most 2 (Int 比较) → 无 E031 (精确提升)', () => {
|
|
57
|
+
assert.ok(!hasMixingError('Rule main produce Bool:\n Return 1.0m at most 2.'));
|
|
58
|
+
});
|
|
59
|
+
it('Decimal.divide(1m, 2m, 2, "HALF_UP") → 无 E031', () => {
|
|
60
|
+
assert.ok(!hasMixingError('Rule main produce Decimal:\n Return Decimal.divide(1m, 2m, 2, "HALF_UP").'));
|
|
61
|
+
});
|
|
62
|
+
it('1.0 equals to 2.0 (纯 Double 比较) → 无 E031', () => {
|
|
63
|
+
assert.ok(!hasMixingError('Rule main produce Bool:\n Return 1.0 equals to 2.0.'));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('Decimal M1 后续 — 合法组合不误报', () => {
|
|
67
|
+
it('1.08m plus 2 (Int) → 无 E031 (精确提升允许)', () => {
|
|
68
|
+
assert.ok(!hasMixingError('Rule main produce Decimal:\n Return 1.08m plus 2.'));
|
|
69
|
+
});
|
|
70
|
+
it('1.08m plus 2.50m (Decimal+Decimal) → 无 E031', () => {
|
|
71
|
+
assert.ok(!hasMixingError('Rule main produce Decimal:\n Return 1.08m plus 2.50m.'));
|
|
72
|
+
});
|
|
73
|
+
it('1.08 plus 2.5 (Double+Double) → 无 E031 (纯 Double 合法)', () => {
|
|
74
|
+
assert.ok(!hasMixingError('Rule main produce Double:\n Return 1.08 plus 2.5.'));
|
|
75
|
+
});
|
|
76
|
+
it('1 plus 2 (Int+Int) → 无 E031', () => {
|
|
77
|
+
assert.ok(!hasMixingError('Rule main produce Int:\n Return 1 plus 2.'));
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=decimal-mixing-typecheck.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-mixing-typecheck.test.js","sourceRoot":"","sources":["../../../test/unit/decimal-mixing-typecheck.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-round-divide.test.d.ts","sourceRoot":"","sources":["../../../test/unit/decimal-round-divide.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { compile } from '../../src/browser.js';
|
|
4
|
+
import { evaluate } from '../../src/core/interpreter.js';
|
|
5
|
+
// Decimal M2(ADR 0025):Decimal.round(x, scale, mode) + Decimal.divide(x, y, scale, mode)。
|
|
6
|
+
// mode 字符串 HALF_UP/HALF_EVEN/DOWN,scale 0..18。三引擎逐位一致(与 truffle BigDecimal
|
|
7
|
+
// setScale/divide(RoundingMode) 对齐,含 2.5→2 银行家舍入 + DOWN 朝零截断 + canonical 去尾零)。
|
|
8
|
+
function runDecimal(body) {
|
|
9
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
10
|
+
assert.ok(c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
11
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
12
|
+
assert.ok(ev.success, `eval: ${ev.error ?? ''}`);
|
|
13
|
+
return ev.value.toFixed();
|
|
14
|
+
}
|
|
15
|
+
function evalErr(body) {
|
|
16
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
17
|
+
if (!c.core)
|
|
18
|
+
return 'COMPILE';
|
|
19
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
20
|
+
return ev.success ? '<no error>' : String(ev.error);
|
|
21
|
+
}
|
|
22
|
+
const R = (expr) => `Rule main given seed as Int, produce Decimal:\n Return ${expr}.`;
|
|
23
|
+
describe('Decimal M2 — round 舍入模式', () => {
|
|
24
|
+
it('2.345m sc2 HALF_UP → 2.35', () => assert.equal(runDecimal(R('Decimal.round(2.345m, 2, "HALF_UP")')), '2.35'));
|
|
25
|
+
it('2.345m sc2 HALF_EVEN → 2.34 (向偶)', () => assert.equal(runDecimal(R('Decimal.round(2.345m, 2, "HALF_EVEN")')), '2.34'));
|
|
26
|
+
it('2.355m sc2 HALF_EVEN → 2.36 (向偶)', () => assert.equal(runDecimal(R('Decimal.round(2.355m, 2, "HALF_EVEN")')), '2.36'));
|
|
27
|
+
it('2.5m sc0 HALF_EVEN → 2 (银行家)', () => assert.equal(runDecimal(R('Decimal.round(2.5m, 0, "HALF_EVEN")')), '2'));
|
|
28
|
+
it('3.5m sc0 HALF_EVEN → 4 (银行家)', () => assert.equal(runDecimal(R('Decimal.round(3.5m, 0, "HALF_EVEN")')), '4'));
|
|
29
|
+
it('2.999m sc0 DOWN → 2 (截断)', () => assert.equal(runDecimal(R('Decimal.round(2.999m, 0, "DOWN")')), '2'));
|
|
30
|
+
it('2.50m sc2 → 2.5 (canonical 去尾零)', () => assert.equal(runDecimal(R('Decimal.round(2.50m, 2, "HALF_UP")')), '2.5'));
|
|
31
|
+
});
|
|
32
|
+
describe('Decimal M2 — divide 精确除法', () => {
|
|
33
|
+
it('10m / 3m sc4 HALF_UP → 3.3333', () => assert.equal(runDecimal(R('Decimal.divide(10m, 3m, 4, "HALF_UP")')), '3.3333'));
|
|
34
|
+
it('2m / 3m sc2 HALF_UP → 0.67', () => assert.equal(runDecimal(R('Decimal.divide(2m, 3m, 2, "HALF_UP")')), '0.67'));
|
|
35
|
+
it('1m / 8m sc2 DOWN → 0.12', () => assert.equal(runDecimal(R('Decimal.divide(1m, 8m, 2, "DOWN")')), '0.12'));
|
|
36
|
+
it('1m / 3m sc2 HALF_EVEN → 0.33', () => assert.equal(runDecimal(R('Decimal.divide(1m, 3m, 2, "HALF_EVEN")')), '0.33'));
|
|
37
|
+
it('100m / 4m sc2 → 25 (整除 canonical)', () => assert.equal(runDecimal(R('Decimal.divide(100m, 4m, 2, "HALF_UP")')), '25'));
|
|
38
|
+
});
|
|
39
|
+
describe('Decimal M2 — 合规场景 (利率/分摊)', () => {
|
|
40
|
+
it('月利率: 年息 7.25% / 12 期, sc6 HALF_EVEN', () => {
|
|
41
|
+
// 0.0725 / 12 = 0.00604166... → sc6 HALF_EVEN = 0.006042
|
|
42
|
+
assert.equal(runDecimal(R('Decimal.divide(0.0725m, 12m, 6, "HALF_EVEN")')), '0.006042');
|
|
43
|
+
});
|
|
44
|
+
it('税额: 108.00m round sc2 = 108', () => assert.equal(runDecimal(R('Decimal.round(100.00m times 1.08m, 2, "HALF_UP")')), '108'));
|
|
45
|
+
});
|
|
46
|
+
describe('Decimal M2 — 错误处理', () => {
|
|
47
|
+
it('除零 → error', () => assert.match(evalErr(R('Decimal.divide(1m, 0m, 2, "HALF_UP")')), /division by zero/i));
|
|
48
|
+
it('未知 mode → error', () => assert.match(evalErr(R('Decimal.round(1.5m, 2, "CEILING")')), /unknown rounding mode/i));
|
|
49
|
+
it('scale 越界(>18) → error', () => assert.match(evalErr(R('Decimal.round(1.5m, 19, "HALF_UP")')), /scale must be/i));
|
|
50
|
+
// 注:负 scale 无法用 CNL 字面量构造(无前缀 -,`-1` 解析失败);runtime 仍校验 n<0,
|
|
51
|
+
// 但只能通过非字面量路径触发(例如 evaluation 输入),此处不测无法构造的输入。
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=decimal-round-divide.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal-round-divide.test.js","sourceRoot":"","sources":["../../../test/unit/decimal-round-divide.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiline-continuation.test.d.ts","sourceRoot":"","sources":["../../../test/unit/multiline-continuation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { compile, evaluate, EN_US, initializeAllBundledLexicons } from '../../src/browser.js';
|
|
4
|
+
// 等缩进多行表达式续行(ADR 0026)—— TS 引擎。续行(与语句起始行同缩进、二元运算符打头/结尾)
|
|
5
|
+
// 解析到与单行**完全相同**的 Core IR(零新节点);双引擎一致由 tier1-parity(multiline_continuation
|
|
6
|
+
// 样本)锁。安全性(Codex 审查 019f157b):只跨等缩进 NEWLINE,不碰 INDENT/DEDENT,块结构零风险。
|
|
7
|
+
initializeAllBundledLexicons();
|
|
8
|
+
function run(body, entry, ctx) {
|
|
9
|
+
const c = compile(`Module probe.\n${body}\n`, { lexicon: EN_US });
|
|
10
|
+
assert.ok(c.success && c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
11
|
+
const ev = evaluate(c.core, entry, ctx);
|
|
12
|
+
assert.ok(ev.success, `eval: ${ev.error ?? ''}`);
|
|
13
|
+
return ev.value;
|
|
14
|
+
}
|
|
15
|
+
function compiles(body) {
|
|
16
|
+
return compile(`Module probe.\n${body}\n`, { lexicon: EN_US }).success;
|
|
17
|
+
}
|
|
18
|
+
/** 剥 origin 的结构指纹,用于比较多行版 ≡ 单行版 Core IR。 */
|
|
19
|
+
function fingerprint(body) {
|
|
20
|
+
const c = compile(`Module probe.\n${body}\n`, { lexicon: EN_US });
|
|
21
|
+
assert.ok(c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
22
|
+
return JSON.stringify(stripOrigin(c.core));
|
|
23
|
+
}
|
|
24
|
+
function stripOrigin(o) {
|
|
25
|
+
if (Array.isArray(o))
|
|
26
|
+
return o.map(stripOrigin);
|
|
27
|
+
if (o && typeof o === 'object') {
|
|
28
|
+
const r = {};
|
|
29
|
+
for (const k of Object.keys(o)) {
|
|
30
|
+
if (k === 'origin' || k === 'span')
|
|
31
|
+
continue;
|
|
32
|
+
r[k] = stripOrigin(o[k]);
|
|
33
|
+
}
|
|
34
|
+
return r;
|
|
35
|
+
}
|
|
36
|
+
return o;
|
|
37
|
+
}
|
|
38
|
+
describe('ADR 0026 — 等缩进多行续行求值正确', () => {
|
|
39
|
+
it('加法链跨行:a plus 10 plus 20 (a=5) = 35', () => {
|
|
40
|
+
assert.equal(run('Rule total given a as Int, produce Int:\n Return a\n plus 10\n plus 20.', 'total', { a: 5 }), 35);
|
|
41
|
+
});
|
|
42
|
+
it('字符串拼接跨行', () => {
|
|
43
|
+
assert.equal(run('Rule g given name as Text, produce Text:\n Return "Hello, "\n plus name\n plus "!".', 'g', { name: 'world' }), 'Hello, world!');
|
|
44
|
+
});
|
|
45
|
+
it('行尾运算符续行:a plus\\n 10', () => {
|
|
46
|
+
assert.equal(run('Rule t given a as Int, produce Int:\n Return a plus\n 10.', 't', { a: 5 }), 15);
|
|
47
|
+
});
|
|
48
|
+
it('乘法链跨行', () => {
|
|
49
|
+
assert.equal(run('Rule s given a as Int, produce Int:\n Return a\n times 2\n times 3.', 's', { a: 4 }), 24);
|
|
50
|
+
});
|
|
51
|
+
it('比较+逻辑跨行', () => {
|
|
52
|
+
assert.equal(run('Rule r given x as Int, produce Bool:\n Return x at least 1\n and x at most 9.', 'r', { x: 5 }), true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('ADR 0026 — 多行版 ≡ 单行版 Core IR(纯解析层)', () => {
|
|
56
|
+
it('加法链:多行与单行结构一致', () => {
|
|
57
|
+
const ml = fingerprint('Rule total given a as Int, produce Int:\n Return a\n plus 10\n plus 20.');
|
|
58
|
+
const sl = fingerprint('Rule total given a as Int, produce Int:\n Return a plus 10 plus 20.');
|
|
59
|
+
assert.equal(ml, sl);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('ADR 0026 — 边界(本批仅等缩进)', () => {
|
|
63
|
+
it('更深缩进续行仍拒(本批不支持)', () => {
|
|
64
|
+
assert.equal(compiles('Rule t given a as Int, produce Int:\n Return a\n plus 1.'), false);
|
|
65
|
+
});
|
|
66
|
+
it('不跨行续接第二个比较(不扩大 TS/Java 链式比较分歧)', () => {
|
|
67
|
+
// Codex 审查 019f157b §5:Java comparisonExpr 单比较非链式。续行若跨行续接第二个比较会
|
|
68
|
+
// 与 Java 分歧 → 故 `a < b\n< c` 多行链式比较不被续行接受(首个比较的行首/行尾续行仍支持)。
|
|
69
|
+
assert.equal(compiles('Rule r given a as Int, produce Bool:\n Return a less than 5\n less than 10.'), false);
|
|
70
|
+
// 但首个比较的行首续行仍可:`a\n< b`。
|
|
71
|
+
assert.equal(run('Rule r given a as Int, produce Bool:\n Return a\n less than 10.', 'r', { a: 5 }), true);
|
|
72
|
+
});
|
|
73
|
+
it('块边界不被续行误并:两条独立语句', () => {
|
|
74
|
+
const c = compile('Module probe.\nRule r given a as Int, produce Int:\n Let m be a plus 1.\n Return m.\n', { lexicon: EN_US });
|
|
75
|
+
assert.ok(c.success && c.core);
|
|
76
|
+
const fn = c.core.decls.find(d => d.kind === 'Func' && d.name === 'r');
|
|
77
|
+
assert.ok(fn && fn.kind === 'Func', 'rule r found');
|
|
78
|
+
assert.equal(fn.body?.statements.length, 2, '应为两条独立语句');
|
|
79
|
+
});
|
|
80
|
+
it('续行不影响行内运算符链(无换行时行为不变)', () => {
|
|
81
|
+
// 回归保护:单行运算符链照常工作,续行逻辑只在 NEWLINE 后命中,不干扰行内解析。
|
|
82
|
+
assert.equal(run('Rule r given a as Int, produce Int:\n Return a plus 1 plus 2 plus 3.', 'r', { a: 0 }), 6);
|
|
83
|
+
// 注:前缀 operatorCall `+(a,b)` 是 Java-grammar-only 形(TS 本就不支持,见 Codex 审查
|
|
84
|
+
// 019f157b 的双引擎差异),与本续行特性无关——续行只在 expr 循环内、NEWLINE 后触发。
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=multiline-continuation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiline-continuation.test.js","sourceRoot":"","sources":["../../../test/unit/multiline-continuation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAE9F,wDAAwD;AACxD,2EAA2E;AAC3E,qEAAqE;AACrE,4BAA4B,EAAE,CAAC;AAE/B,SAAS,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,GAA4B;IACpE,MAAM,CAAC,GAAG,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,CAAE,CAA+B,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACjH,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC;IACjD,OAAO,EAAE,CAAC,KAAK,CAAC;AAClB,CAAC;AACD,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;AACzE,CAAC;AACD,4CAA4C;AAC5C,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,CAAC,GAAG,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,CAAE,CAA+B,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IACpG,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,WAAW,CAAC,CAAU;IAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAA4B,EAAE,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,MAAM;gBAAE,SAAS;YAC7C,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAE,CAA6B,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,4EAA4E,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACzH,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACjB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,wFAAwF,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;IACvJ,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,6DAA6D,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACf,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,wEAAwE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACjH,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACjB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,iFAAiF,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5H,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;QACvB,MAAM,EAAE,GAAG,WAAW,CAAC,4EAA4E,CAAC,CAAC;QACrG,MAAM,EAAE,GAAG,WAAW,CAAC,sEAAsE,CAAC,CAAC;QAC/F,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,8DAA8D,CAAC,EAAE,KAAK,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,gEAAgE;QAChE,4DAA4D;QAC5D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,+EAA+E,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/G,yBAAyB;QACzB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,mEAAmE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,GAAG,OAAO,CAAC,yFAAyF,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACjI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,EAAE,GAAG,CAAC,CAAC,IAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QACxE,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE,cAAc,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,8CAA8C;QAC9C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,uEAAuE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7G,uEAAuE;QACvE,wDAAwD;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tides-ballad.test.d.ts","sourceRoot":"","sources":["../../../test/unit/tides-ballad.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { compile, evaluate, EN_US, initializeAllBundledLexicons } from '../../src/browser.js';
|
|
7
|
+
import { SemanticTokenKind } from '../../src/config/token-kind.js';
|
|
8
|
+
// examples/alias-poem-story/tides.ballad.aster 的 CI 防回归:第二首谣曲展示 Match(behold)分支 +
|
|
9
|
+
// List 生成(List.range/List.sum)+ 等缩进多行续行,全经生产引擎编译执行。与 nightfall 同用 Bard
|
|
10
|
+
// 方言别名(recognition-side,ADR 0022)。
|
|
11
|
+
initializeAllBundledLexicons();
|
|
12
|
+
/** 与 bard.mjs 同源的 Bard 方言(含 Match→behold / When→as)。 */
|
|
13
|
+
const BARD_EN = {
|
|
14
|
+
...EN_US,
|
|
15
|
+
id: 'bard-en',
|
|
16
|
+
name: 'Bard (English)',
|
|
17
|
+
aliases: {
|
|
18
|
+
[SemanticTokenKind.MODULE_DECL]: ['Ballad'],
|
|
19
|
+
[SemanticTokenKind.FUNC_TO]: ['Verse'],
|
|
20
|
+
[SemanticTokenKind.FUNC_GIVEN]: ['of'],
|
|
21
|
+
[SemanticTokenKind.LET]: ['let'],
|
|
22
|
+
[SemanticTokenKind.BE]: ['become'],
|
|
23
|
+
[SemanticTokenKind.IF]: ['where'],
|
|
24
|
+
[SemanticTokenKind.RETURN]: ['sing'],
|
|
25
|
+
[SemanticTokenKind.MATCH]: ['behold'],
|
|
26
|
+
[SemanticTokenKind.WHEN]: ['as'],
|
|
27
|
+
[SemanticTokenKind.PLUS]: ['then'],
|
|
28
|
+
[SemanticTokenKind.AT_MOST]: ['but'],
|
|
29
|
+
[SemanticTokenKind.AT_LEAST]: ['past'],
|
|
30
|
+
[SemanticTokenKind.MINUS_WORD]: ['less'],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
function repoRoot() {
|
|
34
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
35
|
+
for (let i = 0; i < 8; i++) {
|
|
36
|
+
if (existsSync(join(dir, 'package.json')) && existsSync(join(dir, 'examples')))
|
|
37
|
+
return dir;
|
|
38
|
+
dir = dirname(dir);
|
|
39
|
+
}
|
|
40
|
+
throw new Error('repo root (with examples/) not found');
|
|
41
|
+
}
|
|
42
|
+
const TIDES = readFileSync(join(repoRoot(), 'examples', 'alias-poem-story', 'tides.ballad.aster'), 'utf8');
|
|
43
|
+
function seasong(phase) {
|
|
44
|
+
const c = compile(TIDES, { lexicon: BARD_EN });
|
|
45
|
+
assert.ok(c.success && c.core, `tides compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
46
|
+
const ev = evaluate(c.core, 'seasong', { phase });
|
|
47
|
+
assert.ok(ev.success, `seasong: ${ev.error ?? ''}`);
|
|
48
|
+
return String(ev.value);
|
|
49
|
+
}
|
|
50
|
+
describe('examples/alias-poem-story — tides 谣曲 (Match + List)', () => {
|
|
51
|
+
it('Bard 方言源码编译成功', () => {
|
|
52
|
+
const c = compile(TIDES, { lexicon: BARD_EN });
|
|
53
|
+
assert.ok(c.success && c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
54
|
+
});
|
|
55
|
+
it('Match(behold)按月相选 omen,四相各不同(押 -eep 韵)', () => {
|
|
56
|
+
// 第一行(moon 行)押 -eep 韵:deep / sleep / leap / creep。
|
|
57
|
+
assert.match(seasong(0), /^The new moon hides; the cove lies black and deep,/);
|
|
58
|
+
assert.match(seasong(1), /^The crescent leans; the shallows stir from sleep,/);
|
|
59
|
+
assert.match(seasong(2), /^The full moon climbs; the breakers rise to leap,/);
|
|
60
|
+
assert.match(seasong(3), /^The old moon wanes; the long grey waters creep,/);
|
|
61
|
+
});
|
|
62
|
+
it('List 驱动意象(数字退到幕后):swell 高度选潮汐意象,不念数字', () => {
|
|
63
|
+
// swell(count)=List.sum(List.range(1,count)) 算出高度,behold 高度选意象(不印数字);
|
|
64
|
+
// 第二行也押 -eep 韵(keep)。phase p → height = sum(1..p)(半开区间 range(1,p+1))。
|
|
65
|
+
assert.match(seasong(0), /and not one wave to keep\.$/); // height 0
|
|
66
|
+
assert.match(seasong(1), /and a single tide to keep\.$/); // height 1
|
|
67
|
+
assert.match(seasong(2), /and a rising tide to keep\.$/); // height 3
|
|
68
|
+
assert.match(seasong(3), /and a flood the shore will keep\.$/); // height 6
|
|
69
|
+
// 台面上看不到阿拉伯数字。
|
|
70
|
+
assert.doesNotMatch(seasong(3), /[0-9]/);
|
|
71
|
+
});
|
|
72
|
+
it('多行续行 + 分行:seasong 是两行押韵对句', () => {
|
|
73
|
+
const out = seasong(2);
|
|
74
|
+
const lines = out.split('\n');
|
|
75
|
+
assert.equal(lines.length, 2, 'moon 行 + swell 行');
|
|
76
|
+
assert.equal(lines[0], 'The full moon climbs; the breakers rise to leap,');
|
|
77
|
+
assert.equal(lines[1], 'and a rising tide to keep.');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=tides-ballad.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tides-ballad.test.js","sourceRoot":"","sources":["../../../test/unit/tides-ballad.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aster-cloud/aster-lang-ts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Aster CNL (Controlled Natural Language) TypeScript Compiler - Lexer, Parser, AST, Core IR, Type Checker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -116,7 +116,8 @@
|
|
|
116
116
|
},
|
|
117
117
|
"dependencies": {
|
|
118
118
|
"@types/semver": "^7.7.1",
|
|
119
|
-
"semver": "^7.7.3"
|
|
119
|
+
"semver": "^7.7.3",
|
|
120
|
+
"decimal.js": "10.4.3"
|
|
120
121
|
},
|
|
121
122
|
"//peerDependencies": "P0-R19: CLI/LSP-only deps. Consumers importing only the browser/core entries don't need them. Subpath imports (./cli, ./lsp) require them — flagged optional so npm/pnpm install them by default but consumers can opt out with --no-optional.",
|
|
122
123
|
"peerDependencies": {
|