@aster-cloud/aster-lang-ts 1.0.28 → 1.0.30
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/scripts/generate_error_codes.js +49 -6
- package/dist/scripts/generate_error_codes.js.map +1 -1
- package/dist/src/ai/providers/openai.d.ts +10 -0
- package/dist/src/ai/providers/openai.d.ts.map +1 -1
- package/dist/src/ai/providers/openai.js +4 -0
- package/dist/src/ai/providers/openai.js.map +1 -1
- package/dist/src/config/lexicons/regex-guard.d.ts.map +1 -1
- package/dist/src/config/lexicons/regex-guard.js +128 -0
- package/dist/src/config/lexicons/regex-guard.js.map +1 -1
- package/dist/src/core/interpreter.d.ts.map +1 -1
- package/dist/src/core/interpreter.js +221 -27
- package/dist/src/core/interpreter.js.map +1 -1
- package/dist/src/cst/cst_builder.js +0 -14
- package/dist/src/cst/cst_builder.js.map +1 -1
- package/dist/src/cst/cst_printer.d.ts.map +1 -1
- package/dist/src/cst/cst_printer.js +20 -3
- package/dist/src/cst/cst_printer.js.map +1 -1
- package/dist/src/diagnostics/error_codes.d.ts +3 -3
- package/dist/src/diagnostics/error_codes.d.ts.map +1 -1
- package/dist/src/diagnostics/error_codes.js +509 -78
- package/dist/src/diagnostics/error_codes.js.map +1 -1
- package/dist/src/formatter.d.ts +7 -0
- package/dist/src/formatter.d.ts.map +1 -1
- package/dist/src/formatter.js +175 -5
- package/dist/src/formatter.js.map +1 -1
- package/dist/src/frontend/canonicalizer.d.ts.map +1 -1
- package/dist/src/frontend/canonicalizer.js +47 -6
- package/dist/src/frontend/canonicalizer.js.map +1 -1
- package/dist/src/frontend/lexer.d.ts +2 -1
- package/dist/src/frontend/lexer.d.ts.map +1 -1
- package/dist/src/frontend/lexer.js +10 -3
- package/dist/src/frontend/lexer.js.map +1 -1
- package/dist/src/frontend/transformers.d.ts.map +1 -1
- package/dist/src/frontend/transformers.js +50 -3
- package/dist/src/frontend/transformers.js.map +1 -1
- package/dist/src/lower_to_core.js +101 -4
- package/dist/src/lower_to_core.js.map +1 -1
- package/dist/src/lsp/canonicalize-options.d.ts +26 -0
- package/dist/src/lsp/canonicalize-options.d.ts.map +1 -0
- package/dist/src/lsp/canonicalize-options.js +14 -0
- package/dist/src/lsp/canonicalize-options.js.map +1 -0
- package/dist/src/lsp/completion.d.ts.map +1 -1
- package/dist/src/lsp/completion.js +22 -4
- package/dist/src/lsp/completion.js.map +1 -1
- package/dist/src/lsp/server.js +29 -1
- package/dist/src/lsp/server.js.map +1 -1
- package/dist/src/lsp/tenant-init.d.ts +55 -0
- package/dist/src/lsp/tenant-init.d.ts.map +1 -0
- package/dist/src/lsp/tenant-init.js +88 -0
- package/dist/src/lsp/tenant-init.js.map +1 -0
- package/dist/src/mapping/candidate-generator.d.ts +84 -0
- package/dist/src/mapping/candidate-generator.d.ts.map +1 -0
- package/dist/src/mapping/candidate-generator.js +114 -0
- package/dist/src/mapping/candidate-generator.js.map +1 -0
- package/dist/src/mapping/entity-proposer.d.ts +85 -0
- package/dist/src/mapping/entity-proposer.d.ts.map +1 -0
- package/dist/src/mapping/entity-proposer.js +162 -0
- package/dist/src/mapping/entity-proposer.js.map +1 -0
- package/dist/src/mapping/mapping-ir.d.ts +85 -0
- package/dist/src/mapping/mapping-ir.d.ts.map +1 -0
- package/dist/src/mapping/mapping-ir.js +195 -0
- package/dist/src/mapping/mapping-ir.js.map +1 -0
- package/dist/src/mapping/proof-ir.d.ts +125 -0
- package/dist/src/mapping/proof-ir.d.ts.map +1 -0
- package/dist/src/mapping/proof-ir.js +48 -0
- package/dist/src/mapping/proof-ir.js.map +1 -0
- package/dist/src/mapping/quantity-ir.d.ts +93 -0
- package/dist/src/mapping/quantity-ir.d.ts.map +1 -0
- package/dist/src/mapping/quantity-ir.js +151 -0
- package/dist/src/mapping/quantity-ir.js.map +1 -0
- package/dist/src/mapping/source-ir.d.ts +82 -0
- package/dist/src/mapping/source-ir.d.ts.map +1 -0
- package/dist/src/mapping/source-ir.js +231 -0
- package/dist/src/mapping/source-ir.js.map +1 -0
- package/dist/src/nodeid/change-impact.d.ts +77 -0
- package/dist/src/nodeid/change-impact.d.ts.map +1 -0
- package/dist/src/nodeid/change-impact.js +132 -0
- package/dist/src/nodeid/change-impact.js.map +1 -0
- package/dist/src/nodeid/node-id-map.d.ts +69 -0
- package/dist/src/nodeid/node-id-map.d.ts.map +1 -0
- package/dist/src/nodeid/node-id-map.js +193 -0
- package/dist/src/nodeid/node-id-map.js.map +1 -0
- package/dist/src/parser/decl-parser.d.ts.map +1 -1
- package/dist/src/parser/decl-parser.js +10 -4
- package/dist/src/parser/decl-parser.js.map +1 -1
- package/dist/src/parser/expr-stmt-parser.d.ts.map +1 -1
- package/dist/src/parser/expr-stmt-parser.js +36 -24
- package/dist/src/parser/expr-stmt-parser.js.map +1 -1
- package/dist/src/parser/span-utils.d.ts +25 -0
- package/dist/src/parser/span-utils.d.ts.map +1 -1
- package/dist/src/parser/span-utils.js +43 -0
- package/dist/src/parser/span-utils.js.map +1 -1
- package/dist/src/parser/type-parser.d.ts.map +1 -1
- package/dist/src/parser/type-parser.js +21 -0
- package/dist/src/parser/type-parser.js.map +1 -1
- package/dist/src/typecheck/expression.d.ts.map +1 -1
- package/dist/src/typecheck/expression.js +26 -0
- package/dist/src/typecheck/expression.js.map +1 -1
- package/dist/test/fuzz/fuzz.test.js +62 -2
- package/dist/test/fuzz/fuzz.test.js.map +1 -1
- package/dist/test/unit/call-arity.test.d.ts +2 -0
- package/dist/test/unit/call-arity.test.d.ts.map +1 -0
- package/dist/test/unit/call-arity.test.js +71 -0
- package/dist/test/unit/call-arity.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/canonicalizer.test.js +42 -4
- package/dist/test/unit/canonicalizer/canonicalizer.test.js.map +1 -1
- package/dist/test/unit/canonicalizer/line-preservation.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.js +71 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.js +98 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.js +101 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.js.map +1 -0
- package/dist/test/unit/formatter-redos.test.d.ts +2 -0
- package/dist/test/unit/formatter-redos.test.d.ts.map +1 -0
- package/dist/test/unit/formatter-redos.test.js +196 -0
- package/dist/test/unit/formatter-redos.test.js.map +1 -0
- package/dist/test/unit/interpreter/interpreter.test.js +7 -2
- package/dist/test/unit/interpreter/interpreter.test.js.map +1 -1
- package/dist/test/unit/lexer/bom.test.d.ts +2 -0
- package/dist/test/unit/lexer/bom.test.d.ts.map +1 -0
- package/dist/test/unit/lexer/bom.test.js +49 -0
- package/dist/test/unit/lexer/bom.test.js.map +1 -0
- package/dist/test/unit/list-get-bounds.test.d.ts +2 -0
- package/dist/test/unit/list-get-bounds.test.d.ts.map +1 -0
- package/dist/test/unit/list-get-bounds.test.js +66 -0
- package/dist/test/unit/list-get-bounds.test.js.map +1 -0
- package/dist/test/unit/long-bigint-exact.test.d.ts +2 -0
- package/dist/test/unit/long-bigint-exact.test.d.ts.map +1 -0
- package/dist/test/unit/long-bigint-exact.test.js +79 -0
- package/dist/test/unit/long-bigint-exact.test.js.map +1 -0
- package/dist/test/unit/lsp/completion-lexicon.test.d.ts +2 -0
- package/dist/test/unit/lsp/completion-lexicon.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/completion-lexicon.test.js +83 -0
- package/dist/test/unit/lsp/completion-lexicon.test.js.map +1 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.d.ts +2 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.js +187 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.js.map +1 -0
- package/dist/test/unit/map-builtins.test.js +163 -3
- package/dist/test/unit/map-builtins.test.js.map +1 -1
- package/dist/test/unit/map-structural-equality.test.d.ts +2 -0
- package/dist/test/unit/map-structural-equality.test.d.ts.map +1 -0
- package/dist/test/unit/map-structural-equality.test.js +64 -0
- package/dist/test/unit/map-structural-equality.test.js.map +1 -0
- package/dist/test/unit/map-type-guard.test.js +8 -5
- package/dist/test/unit/map-type-guard.test.js.map +1 -1
- package/dist/test/unit/mapping/candidate-generator.test.d.ts +2 -0
- package/dist/test/unit/mapping/candidate-generator.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/candidate-generator.test.js +177 -0
- package/dist/test/unit/mapping/candidate-generator.test.js.map +1 -0
- package/dist/test/unit/mapping/entity-proposer.test.d.ts +2 -0
- package/dist/test/unit/mapping/entity-proposer.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/entity-proposer.test.js +168 -0
- package/dist/test/unit/mapping/entity-proposer.test.js.map +1 -0
- package/dist/test/unit/mapping/mapping-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/mapping-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/mapping-ir.test.js +144 -0
- package/dist/test/unit/mapping/mapping-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/proof-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/proof-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/proof-ir.test.js +119 -0
- package/dist/test/unit/mapping/proof-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/quantity-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/quantity-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/quantity-ir.test.js +144 -0
- package/dist/test/unit/mapping/quantity-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.d.ts +2 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.js +182 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.js.map +1 -0
- package/dist/test/unit/mapping/redos-budget.test.d.ts +2 -0
- package/dist/test/unit/mapping/redos-budget.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/redos-budget.test.js +168 -0
- package/dist/test/unit/mapping/redos-budget.test.js.map +1 -0
- package/dist/test/unit/mapping/source-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/source-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/source-ir.test.js +113 -0
- package/dist/test/unit/mapping/source-ir.test.js.map +1 -0
- package/dist/test/unit/nodeid/change-impact.test.d.ts +2 -0
- package/dist/test/unit/nodeid/change-impact.test.d.ts.map +1 -0
- package/dist/test/unit/nodeid/change-impact.test.js +152 -0
- package/dist/test/unit/nodeid/change-impact.test.js.map +1 -0
- package/dist/test/unit/nodeid/rename-declaration.test.d.ts +2 -0
- package/dist/test/unit/nodeid/rename-declaration.test.d.ts.map +1 -0
- package/dist/test/unit/nodeid/rename-declaration.test.js +75 -0
- package/dist/test/unit/nodeid/rename-declaration.test.js.map +1 -0
- package/dist/test/unit/parse-type-recursion.test.d.ts +2 -0
- package/dist/test/unit/parse-type-recursion.test.d.ts.map +1 -0
- package/dist/test/unit/parse-type-recursion.test.js +58 -0
- package/dist/test/unit/parse-type-recursion.test.js.map +1 -0
- package/dist/test/unit/regex-guard.test.js +64 -0
- package/dist/test/unit/regex-guard.test.js.map +1 -1
- package/dist/test/unit/strict-int-coercion.test.d.ts +2 -0
- package/dist/test/unit/strict-int-coercion.test.d.ts.map +1 -0
- package/dist/test/unit/strict-int-coercion.test.js +96 -0
- package/dist/test/unit/strict-int-coercion.test.js.map +1 -0
- package/dist/test/unit/ufcs-receiver.test.d.ts +2 -0
- package/dist/test/unit/ufcs-receiver.test.d.ts.map +1 -0
- package/dist/test/unit/ufcs-receiver.test.js +75 -0
- package/dist/test/unit/ufcs-receiver.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
/**
|
|
6
|
+
* 严格整型换算(issue aster-lang-ts#144)。
|
|
7
|
+
*
|
|
8
|
+
* ★真实缺陷:`Date.*` / `List.range` / `List.get` / `List.slice` / `Text.substring`
|
|
9
|
+
* 用裸 `Number()` 强转。`Number("x")` 得 `NaN` 后**所有防线同时失效**——
|
|
10
|
+
* `NaN < MIN || NaN > MAX` 两侧都是 false 于是放行;`size > MAX_RANGE_SIZE` 同理,
|
|
11
|
+
* 然后循环零次静默返回 `[]`。非法输入不报错,反而产出「看起来正常」的决策值。
|
|
12
|
+
*
|
|
13
|
+
* 实测(修复前):
|
|
14
|
+
*
|
|
15
|
+
* Date.daysBetween("x","b") → success:true, value:NaN
|
|
16
|
+
* Date.addDays("x",5) greater than 0 → success:true, value:false
|
|
17
|
+
* List.length(List.range("a",5)) → success:true, value:0
|
|
18
|
+
*
|
|
19
|
+
* 而 truffle 同输入抛 `NumberFormatException`——**同一条规则两引擎一个静默出错答案、
|
|
20
|
+
* 一个响亮失败**。对合规引擎,静默的那个远更危险:错误答案会一路流进裁决结果。
|
|
21
|
+
*/
|
|
22
|
+
function run(body) {
|
|
23
|
+
const c = compile(`Module probe.\n${body}\n`);
|
|
24
|
+
assert.ok(c.core, `compile: ${JSON.stringify(c.parseErrors ?? [])}`);
|
|
25
|
+
const ev = evaluate(c.core, 'main', { seed: 0 });
|
|
26
|
+
return { success: ev.success, value: ev.value, error: String(ev.error ?? '') };
|
|
27
|
+
}
|
|
28
|
+
function expectLoudFailure(body, mustMention) {
|
|
29
|
+
const r = run(body);
|
|
30
|
+
assert.equal(r.success, false, `必须响亮失败,实际 success=true value=${JSON.stringify(r.value)}`);
|
|
31
|
+
assert.match(r.error, /expected Int/, `错误信息须指明期望 Int;实际:${r.error}`);
|
|
32
|
+
assert.ok(r.error.includes(mustMention), `错误信息须点名出问题的 builtin(${mustMention}),否则用户无从定位;实际:${r.error}`);
|
|
33
|
+
}
|
|
34
|
+
describe('非法整型入参必须响亮失败(不得静默产 NaN)', () => {
|
|
35
|
+
it('★Date.daysBetween 非数字字符串(此前 success:true, value:NaN)', () => {
|
|
36
|
+
expectLoudFailure('Rule main produce Int:\n Return Date.daysBetween("x", "b").', 'Date.daysBetween');
|
|
37
|
+
});
|
|
38
|
+
it('★Date.addDays 非数字字符串(此前静默产出 false 决策)', () => {
|
|
39
|
+
// 这条最能说明危害:NaN 参与比较后产出一个**看似正常的布尔裁决**。
|
|
40
|
+
expectLoudFailure('Rule main produce Bool:\n Return Date.addDays("x", 5) greater than 0.', 'Date.addDays');
|
|
41
|
+
});
|
|
42
|
+
it('★List.range 非数字字符串(此前静默返回空列表)', () => {
|
|
43
|
+
expectLoudFailure('Rule main produce Int:\n Return List.length(List.range("a", 5)).', 'List.range');
|
|
44
|
+
});
|
|
45
|
+
it('List.get / List.slice / Text.substring 同样收口', () => {
|
|
46
|
+
expectLoudFailure('Rule main produce Int:\n Return List.get([1, 2, 3], "x").', 'List.get');
|
|
47
|
+
expectLoudFailure('Rule main produce Int:\n Return List.length(List.slice([1, 2, 3], "x", 2)).', 'List.slice');
|
|
48
|
+
expectLoudFailure('Rule main produce Text:\n Return Text.substring("hello", "x").', 'Text.substring');
|
|
49
|
+
});
|
|
50
|
+
it('★小数字符串被拒(对齐 Integer.parseInt,不接受 "5.0")', () => {
|
|
51
|
+
expectLoudFailure('Rule main produce Int:\n Return List.length(List.range("5.0", 9)).', 'List.range');
|
|
52
|
+
});
|
|
53
|
+
it('★十六进制字符串被拒(裸 Number("0x10") 会读成 16,Java 侧拒绝)', () => {
|
|
54
|
+
// 与 decimalScale 里已记录的同一类分叉:JS 的宽松数字解析会与 Java 分叉。
|
|
55
|
+
expectLoudFailure('Rule main produce Int:\n Return List.length(List.range("0x10", 99)).', 'List.range');
|
|
56
|
+
});
|
|
57
|
+
it('★空串与纯空白被拒(Number("") 是 0,会静默变成合法索引)', () => {
|
|
58
|
+
expectLoudFailure('Rule main produce Int:\n Return List.get([1, 2, 3], "").', 'List.get');
|
|
59
|
+
expectLoudFailure('Rule main produce Int:\n Return List.get([1, 2, 3], " ").', 'List.get');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('合法输入行为不变(反向护栏)', () => {
|
|
63
|
+
// ★没有这一组,把 toInt 写成「一律抛错」也能让上面全部变绿。
|
|
64
|
+
it('List.range 正常', () => {
|
|
65
|
+
const r = run('Rule main produce Int:\n Return List.length(List.range(1, 5)).');
|
|
66
|
+
assert.equal(r.success, true, r.error);
|
|
67
|
+
assert.equal(r.value, 4);
|
|
68
|
+
});
|
|
69
|
+
it('Date.addDays 正常', () => {
|
|
70
|
+
const r = run('Rule main produce Int:\n Return Date.addDays(Date.fromISO("2026-01-01"), 5).');
|
|
71
|
+
assert.equal(r.success, true, r.error);
|
|
72
|
+
assert.equal(r.value, 20459);
|
|
73
|
+
});
|
|
74
|
+
it('List.get 正常', () => {
|
|
75
|
+
const r = run('Rule main produce Int:\n Return List.get([10, 20, 30], 1).');
|
|
76
|
+
assert.equal(r.success, true, r.error);
|
|
77
|
+
assert.equal(r.value, 20);
|
|
78
|
+
});
|
|
79
|
+
it('★数字字符串仍被接受(对齐 Integer.parseInt 收 "5")', () => {
|
|
80
|
+
const r = run('Rule main produce Int:\n Return List.length(List.range("1", 5)).');
|
|
81
|
+
assert.equal(r.success, true, r.error);
|
|
82
|
+
assert.equal(r.value, 4);
|
|
83
|
+
});
|
|
84
|
+
it('★负数与前后空白仍被接受(parseInt 亦然)', () => {
|
|
85
|
+
const r = run('Rule main produce Int:\n Return List.length(List.range("-2", 2)).');
|
|
86
|
+
assert.equal(r.success, true, r.error);
|
|
87
|
+
assert.equal(r.value, 4);
|
|
88
|
+
});
|
|
89
|
+
it('★Double 入参按截断取整(对齐 Java Number.intValue())', () => {
|
|
90
|
+
// 不是拒绝——truffle 的 toInt 对 Number 走 intValue() 截断,必须一致。
|
|
91
|
+
const r = run('Rule main produce Int:\n Return List.get([10, 20, 30], 1.9).');
|
|
92
|
+
assert.equal(r.success, true, r.error);
|
|
93
|
+
assert.equal(r.value, 20, '1.9 应截断为 1');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=strict-int-coercion.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strict-int-coercion.test.js","sourceRoot":"","sources":["../../../test/unit/strict-int-coercion.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ufcs-receiver.test.d.ts","sourceRoot":"","sources":["../../../test/unit/ufcs-receiver.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
/**
|
|
8
|
+
* UFCS(接收者转参数):`value.sum(1, 2)` → `sum(value, 1, 2)`。
|
|
9
|
+
*
|
|
10
|
+
* <p>这是 Java 引擎有意设计的调用约定(`AstBuilder.applyCallSuffix`,由
|
|
11
|
+
* `AstBuilderTest.testMethodCallTransformsReceiver` 钉住),TS 侧此前缺失,
|
|
12
|
+
* 导致同一段源码在两个引擎上**实际传参个数不同**——不是表示差异,是行为差异:
|
|
13
|
+
*
|
|
14
|
+
* <pre>
|
|
15
|
+
* io.verify(user, pass)
|
|
16
|
+
* Java → Call(Name "verify", [io, user, pass]) 3 参
|
|
17
|
+
* TS → Call(Name "io.verify", [user, pass]) 2 参 ← 分叉
|
|
18
|
+
* </pre>
|
|
19
|
+
*
|
|
20
|
+
* <p>★触发条件是 lexer 的 IDENT / TYPE_IDENT 之分,**不是**「首字母是否大写」:
|
|
21
|
+
* ASCII 小写或下划线开头 → IDENT → 走 UFCS;其余(大写、CJK…)→ TYPE_IDENT → 不拆分。
|
|
22
|
+
*/
|
|
23
|
+
function callOf(expr) {
|
|
24
|
+
const src = `Module p.\n\nRule r, produce:\n Return ${expr}.\n`;
|
|
25
|
+
const ast = parse(lex(canonicalize(src))).ast;
|
|
26
|
+
const ir = JSON.parse(JSON.stringify(lowerModule(ast)));
|
|
27
|
+
const call = ir.decls[0].body.statements[0].expr;
|
|
28
|
+
return { target: call.target?.name, args: call.args };
|
|
29
|
+
}
|
|
30
|
+
describe('UFCS 接收者转参数(与 Java 引擎对齐)', () => {
|
|
31
|
+
it('★小写接收者:`value.sum(1, 2)` → `sum(value, 1, 2)`', () => {
|
|
32
|
+
const { target, args } = callOf('value.sum(1, 2)');
|
|
33
|
+
assert.strictEqual(target, 'sum', '调用目标应是方法名 `sum`(接收者已转为首个实参)。');
|
|
34
|
+
assert.strictEqual(args.length, 3, `实参应为 3 个(接收者 + 2 个原参),实际 ${args.length}`
|
|
35
|
+
+ '\n★若为 2,说明未做 UFCS,与 Java 引擎的实际传参个数不一致。');
|
|
36
|
+
assert.strictEqual(args[0].name, 'value', '首个实参应是接收者 `value`。');
|
|
37
|
+
});
|
|
38
|
+
it('多段限定名:接收者只取**首段**(`a.b.c(1)` → 方法 `b.c`,接收者 `a`)', () => {
|
|
39
|
+
// 与 Java `combineName(null, pendingMembers)` 一致:除首段外全部并入方法名。
|
|
40
|
+
const { target, args } = callOf('a.b.c(1)');
|
|
41
|
+
assert.strictEqual(target, 'b.c', '方法名应是除首段外的全部段。');
|
|
42
|
+
assert.strictEqual(args[0].name, 'a', '接收者应只取首段。');
|
|
43
|
+
assert.strictEqual(args.length, 2);
|
|
44
|
+
});
|
|
45
|
+
it('★大写接收者不拆分:`Text.concat(a, b)` 保持限定名', () => {
|
|
46
|
+
// 反向守卫。没有这条,「UFCS」可以退化成「所有带点的名字都拆」——
|
|
47
|
+
// 那会把 Text.concat / Http.get / Map.get 这些**类型/模块限定名**一并拆坏,
|
|
48
|
+
// 而上面那条正向用例照样绿。
|
|
49
|
+
const { target, args } = callOf('Text.concat(1, 2)');
|
|
50
|
+
assert.strictEqual(target, 'Text.concat', '大写开头是类型/模块限定名,必须整体作为调用目标,不得拆分。');
|
|
51
|
+
assert.strictEqual(args.length, 2, '实参应仍为 2 个(没有多塞接收者)。');
|
|
52
|
+
});
|
|
53
|
+
it('★`Map.get` 同样不拆分(Map 有独立 lexer token,易被漏掉)', () => {
|
|
54
|
+
const { target, args } = callOf('Map.get(1, 2)');
|
|
55
|
+
assert.strictEqual(target, 'Map.get');
|
|
56
|
+
assert.strictEqual(args.length, 2);
|
|
57
|
+
});
|
|
58
|
+
it('无点的普通调用不受影响', () => {
|
|
59
|
+
const { target, args } = callOf('sum(1, 2)');
|
|
60
|
+
assert.strictEqual(target, 'sum');
|
|
61
|
+
assert.strictEqual(args.length, 2, '无接收者可转,实参个数不应变化。');
|
|
62
|
+
});
|
|
63
|
+
it('★拆出的接收者与方法名都必须带 origin(否则在 OriginMap 里不可达)', () => {
|
|
64
|
+
// 与 `Let "_"` 内层 Call 缺 origin 是同一类问题:节点没有位置信息时,
|
|
65
|
+
// ADR 0032 的 trace 锚点与 ADR 0037 的双向导航都定位不到它——不报错,
|
|
66
|
+
// 只是这段代码从导航里静默消失。
|
|
67
|
+
const src = 'Module p.\n\nRule r, produce:\n Return value.sum(1).\n';
|
|
68
|
+
const ast = parse(lex(canonicalize(src))).ast;
|
|
69
|
+
const call = JSON.parse(JSON.stringify(lowerModule(ast)))
|
|
70
|
+
.decls[0].body.statements[0].expr;
|
|
71
|
+
assert.ok(call.target?.origin, '方法名节点缺少 origin。');
|
|
72
|
+
assert.ok(call.args[0]?.origin, '接收者节点缺少 origin。');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=ufcs-receiver.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ufcs-receiver.test.js","sourceRoot":"","sources":["../../../test/unit/ufcs-receiver.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED