@aster-cloud/aster-lang-ts 1.0.32 → 1.0.33
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/corpus-loader.d.ts +10 -4
- package/dist/scripts/corpus-loader.d.ts.map +1 -1
- package/dist/scripts/corpus-loader.js +24 -9
- package/dist/scripts/corpus-loader.js.map +1 -1
- package/dist/scripts/lexicon-completeness.d.ts +42 -0
- package/dist/scripts/lexicon-completeness.d.ts.map +1 -0
- package/dist/scripts/lexicon-completeness.js +57 -0
- package/dist/scripts/lexicon-completeness.js.map +1 -0
- package/dist/scripts/lsp-client-helper.d.ts +7 -1
- package/dist/scripts/lsp-client-helper.d.ts.map +1 -1
- package/dist/scripts/lsp-client-helper.js +6 -1
- package/dist/scripts/lsp-client-helper.js.map +1 -1
- package/dist/scripts/verify-lexicon-sync.js +14 -44
- package/dist/scripts/verify-lexicon-sync.js.map +1 -1
- package/dist/src/lsp/codeaction.d.ts.map +1 -1
- package/dist/src/lsp/codeaction.js +12 -4
- package/dist/src/lsp/codeaction.js.map +1 -1
- package/dist/src/lsp/diagnostics.d.ts +2 -0
- package/dist/src/lsp/diagnostics.d.ts.map +1 -1
- package/dist/src/lsp/diagnostics.js +4 -0
- package/dist/src/lsp/diagnostics.js.map +1 -1
- package/dist/src/lsp/navigation/hover.d.ts.map +1 -1
- package/dist/src/lsp/navigation/hover.js +23 -0
- package/dist/src/lsp/navigation/hover.js.map +1 -1
- package/dist/src/lsp/navigation/references.d.ts +3 -1
- package/dist/src/lsp/navigation/references.d.ts.map +1 -1
- package/dist/src/lsp/navigation/references.js +16 -6
- package/dist/src/lsp/navigation/references.js.map +1 -1
- package/dist/src/lsp/navigation/rename.d.ts +1 -1
- package/dist/src/lsp/navigation/rename.d.ts.map +1 -1
- package/dist/src/lsp/navigation/rename.js +31 -42
- package/dist/src/lsp/navigation/rename.js.map +1 -1
- package/dist/src/lsp/navigation/shared.d.ts +34 -2
- package/dist/src/lsp/navigation/shared.d.ts.map +1 -1
- package/dist/src/lsp/navigation/shared.js +88 -10
- package/dist/src/lsp/navigation/shared.js.map +1 -1
- package/dist/src/lsp/navigation.js +2 -2
- package/dist/src/lsp/navigation.js.map +1 -1
- package/dist/src/lsp/parse-document.d.ts +11 -0
- package/dist/src/lsp/parse-document.d.ts.map +1 -0
- package/dist/src/lsp/parse-document.js +51 -0
- package/dist/src/lsp/parse-document.js.map +1 -0
- package/dist/src/lsp/server.js +18 -23
- package/dist/src/lsp/server.js.map +1 -1
- package/dist/src/lsp/settings.d.ts +35 -0
- package/dist/src/lsp/settings.d.ts.map +1 -0
- package/dist/src/lsp/settings.js +31 -0
- package/dist/src/lsp/settings.js.map +1 -0
- package/dist/src/lsp/source-positions.d.ts +47 -0
- package/dist/src/lsp/source-positions.d.ts.map +1 -0
- package/dist/src/lsp/source-positions.js +92 -0
- package/dist/src/lsp/source-positions.js.map +1 -0
- package/dist/src/lsp/workspace/document-indexer.d.ts +3 -1
- package/dist/src/lsp/workspace/document-indexer.d.ts.map +1 -1
- package/dist/src/lsp/workspace/document-indexer.js +5 -7
- package/dist/src/lsp/workspace/document-indexer.js.map +1 -1
- package/dist/src/lsp/workspace/symbol-finder.d.ts +8 -1
- package/dist/src/lsp/workspace/symbol-finder.d.ts.map +1 -1
- package/dist/src/lsp/workspace/symbol-finder.js +10 -13
- package/dist/src/lsp/workspace/symbol-finder.js.map +1 -1
- package/dist/src/parser/constraint-parser.d.ts.map +1 -1
- package/dist/src/parser/constraint-parser.js +18 -7
- package/dist/src/parser/constraint-parser.js.map +1 -1
- package/dist/src/parser/decl-parser.d.ts.map +1 -1
- package/dist/src/parser/decl-parser.js +6 -5
- 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 +42 -37
- package/dist/src/parser/expr-stmt-parser.js.map +1 -1
- package/dist/src/parser/import-parser.d.ts.map +1 -1
- package/dist/src/parser/import-parser.js +2 -1
- package/dist/src/parser/import-parser.js.map +1 -1
- package/dist/src/parser/keyword-display.d.ts +40 -0
- package/dist/src/parser/keyword-display.d.ts.map +1 -0
- package/dist/src/parser/keyword-display.js +73 -0
- package/dist/src/parser/keyword-display.js.map +1 -0
- package/dist/src/parser/type-parser.d.ts.map +1 -1
- package/dist/src/parser/type-parser.js +5 -4
- package/dist/src/parser/type-parser.js.map +1 -1
- package/dist/src/parser.d.ts.map +1 -1
- package/dist/src/parser.js +1 -0
- package/dist/src/parser.js.map +1 -1
- package/dist/test/integration/lsp/lsp-rename-safety.test.d.ts +2 -0
- package/dist/test/integration/lsp/lsp-rename-safety.test.d.ts.map +1 -0
- package/dist/test/integration/lsp/lsp-rename-safety.test.js +114 -0
- package/dist/test/integration/lsp/lsp-rename-safety.test.js.map +1 -0
- package/dist/test/integration/lsp/lsp-source-positions.test.d.ts +2 -0
- package/dist/test/integration/lsp/lsp-source-positions.test.d.ts.map +1 -0
- package/dist/test/integration/lsp/lsp-source-positions.test.js +161 -0
- package/dist/test/integration/lsp/lsp-source-positions.test.js.map +1 -0
- package/dist/test/integration/lsp/lsp-zh-inmemory-navigation.test.d.ts +2 -0
- package/dist/test/integration/lsp/lsp-zh-inmemory-navigation.test.d.ts.map +1 -0
- package/dist/test/integration/lsp/lsp-zh-inmemory-navigation.test.js +79 -0
- package/dist/test/integration/lsp/lsp-zh-inmemory-navigation.test.js.map +1 -0
- package/dist/test/unit/lexicon-completeness.test.d.ts +2 -0
- package/dist/test/unit/lexicon-completeness.test.d.ts.map +1 -0
- package/dist/test/unit/lexicon-completeness.test.js +42 -0
- package/dist/test/unit/lexicon-completeness.test.js.map +1 -0
- package/dist/test/unit/lsp/codeaction.test.js +28 -0
- package/dist/test/unit/lsp/codeaction.test.js.map +1 -1
- package/dist/test/unit/lsp/lsp-locale-fixes.test.d.ts +2 -0
- package/dist/test/unit/lsp/lsp-locale-fixes.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/lsp-locale-fixes.test.js +105 -0
- package/dist/test/unit/lsp/lsp-locale-fixes.test.js.map +1 -0
- package/dist/test/unit/lsp/parse-document.test.d.ts +2 -0
- package/dist/test/unit/lsp/parse-document.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/parse-document.test.js +30 -0
- package/dist/test/unit/lsp/parse-document.test.js.map +1 -0
- package/dist/test/unit/parser/keyword-display.test.d.ts +8 -0
- package/dist/test/unit/parser/keyword-display.test.d.ts.map +1 -0
- package/dist/test/unit/parser/keyword-display.test.js +27 -0
- package/dist/test/unit/parser/keyword-display.test.js.map +1 -0
- package/dist/test/unit/parser/localized-diagnostic-keywords.test.d.ts +15 -0
- package/dist/test/unit/parser/localized-diagnostic-keywords.test.d.ts.map +1 -0
- package/dist/test/unit/parser/localized-diagnostic-keywords.test.js +98 -0
- package/dist/test/unit/parser/localized-diagnostic-keywords.test.js.map +1 -0
- package/dist/test/unit/parser/prefix-operator-call.test.js +8 -6
- package/dist/test/unit/parser/prefix-operator-call.test.js.map +1 -1
- package/dist/test/unit/scripts/corpus-loader.test.js +44 -9
- package/dist/test/unit/scripts/corpus-loader.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { kw, kwKind, kwKindq, kwq } from './keyword-display.js';
|
|
2
|
+
import { SemanticTokenKind } from '../config/token-kind.js';
|
|
1
3
|
import { kwParts, tokLowerAt, tryReadTranslatedIdent } from './context.js';
|
|
2
4
|
import { TokenKind, KW } from '../frontend/tokens.js';
|
|
3
5
|
import { Node } from '../ast/ast.js';
|
|
@@ -225,11 +227,11 @@ function skipInlineElseLayout(ctx) {
|
|
|
225
227
|
function parseInlineIf(ctx, error, cond) {
|
|
226
228
|
skipInlineThenLayout(ctx);
|
|
227
229
|
if (!ctx.isKeyword(KW.THEN))
|
|
228
|
-
error(
|
|
230
|
+
error(`Expected ${kwq(ctx, KW.THEN)} in inline if`);
|
|
229
231
|
ctx.nextWord();
|
|
230
232
|
// then 分支:单个 return(内联,不带句点;句点由整条 inline-if 末尾的 return 承担)。
|
|
231
233
|
if (!ctx.isKeyword(KW.RETURN))
|
|
232
|
-
error(
|
|
234
|
+
error(`Expected ${kwq(ctx, KW.RETURN)} after ${kwq(ctx, KW.THEN)}`);
|
|
233
235
|
const thenRetTok = ctx.peek();
|
|
234
236
|
ctx.nextWord();
|
|
235
237
|
const thenExpr = parseExpr(ctx, error);
|
|
@@ -258,7 +260,7 @@ function parseInlineIf(ctx, error, cond) {
|
|
|
258
260
|
else {
|
|
259
261
|
// else return X.(末尾 return,带句点)。
|
|
260
262
|
if (!ctx.isKeyword(KW.RETURN))
|
|
261
|
-
error(
|
|
263
|
+
error(`Expected ${kwq(ctx, KW.RETURN)} or ${kwq(ctx, KW.IF)} after ${kwKindq(ctx, SemanticTokenKind.OTHERWISE, 'else')}`);
|
|
262
264
|
const elseRetTok = ctx.peek();
|
|
263
265
|
ctx.nextWord();
|
|
264
266
|
const elseExpr = parseExpr(ctx, error);
|
|
@@ -359,7 +361,7 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
359
361
|
ctx.nextWord();
|
|
360
362
|
const nameTok = ctx.peek();
|
|
361
363
|
const name = parseIdent(ctx, error);
|
|
362
|
-
expectKeyword(ctx, error, KW.BE,
|
|
364
|
+
expectKeyword(ctx, error, KW.BE, `Use ${kwq(ctx, KW.BE)} in bindings: '${kw(ctx, KW.LET, 'Let')} x ${kw(ctx, KW.BE)} ...'.`);
|
|
363
365
|
// Special-case lambda block form to avoid trailing '.'
|
|
364
366
|
if ((ctx.isKeyword('a') && tokLowerAt(ctx, ctx.index + 1) === 'function') || ctx.isKeyword('function')) {
|
|
365
367
|
if (ctx.isKeyword('a'))
|
|
@@ -367,7 +369,7 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
367
369
|
const functionTok = ctx.nextWord(); // 'function'
|
|
368
370
|
const params = parseParamList(ctx, error);
|
|
369
371
|
expectCommaOr(ctx);
|
|
370
|
-
expectKeyword(ctx, error, KW.PRODUCE,
|
|
372
|
+
expectKeyword(ctx, error, KW.PRODUCE, `Expected ${kwq(ctx, KW.PRODUCE)} and return type`);
|
|
371
373
|
let retType;
|
|
372
374
|
if (ctx.at(TokenKind.COLON)) {
|
|
373
375
|
retType = Node.TypeName('Unknown');
|
|
@@ -403,7 +405,7 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
403
405
|
const setTok = ctx.peek();
|
|
404
406
|
ctx.nextWord();
|
|
405
407
|
const name = parseIdent(ctx, error);
|
|
406
|
-
expectKeyword(ctx, error, KW.TO_WORD,
|
|
408
|
+
expectKeyword(ctx, error, KW.TO_WORD, `Use ${kwq(ctx, KW.TO_WORD)} in assignments: '${kw(ctx, KW.SET, 'Set')} x ${kw(ctx, KW.TO_WORD)} ...'.`);
|
|
407
409
|
const expr = parseExpr(ctx, error);
|
|
408
410
|
expectPeriodEnd(ctx, error);
|
|
409
411
|
const nd = Node.Set(name, expr);
|
|
@@ -521,9 +523,9 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
521
523
|
}
|
|
522
524
|
if (ctx.isKeyword(KW.WITHIN)) {
|
|
523
525
|
ctx.nextWord();
|
|
524
|
-
expectKeyword(ctx, error, KW.SCOPE,
|
|
526
|
+
expectKeyword(ctx, error, KW.SCOPE, `Expected ${kwq(ctx, KW.SCOPE)} after ${kwq(ctx, KW.WITHIN, 'Within')}`);
|
|
525
527
|
if (!ctx.at(TokenKind.COLON))
|
|
526
|
-
error(
|
|
528
|
+
error(`Expected ':' after ${kwq(ctx, KW.SCOPE)}`);
|
|
527
529
|
ctx.next();
|
|
528
530
|
expectNewline(ctx, error);
|
|
529
531
|
return parseBlock(ctx, error); // Lowering later
|
|
@@ -531,8 +533,8 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
531
533
|
if (ctx.isKeyword(KW.START)) {
|
|
532
534
|
const startTok = ctx.nextWord();
|
|
533
535
|
const name = parseIdent(ctx, error);
|
|
534
|
-
expectKeyword(ctx, error, KW.AS,
|
|
535
|
-
expectKeyword(ctx, error, KW.ASYNC,
|
|
536
|
+
expectKeyword(ctx, error, KW.AS, `Expected ${kwq(ctx, KW.AS)} after name`);
|
|
537
|
+
expectKeyword(ctx, error, KW.ASYNC, `Expected ${kwq(ctx, KW.ASYNC)}`);
|
|
536
538
|
const expr = parseExpr(ctx, error);
|
|
537
539
|
expectPeriodEnd(ctx, error);
|
|
538
540
|
const nd = Node.Start(name, expr);
|
|
@@ -565,9 +567,9 @@ export function parseStatement(ctx, error, reportOutcomeError = error) {
|
|
|
565
567
|
}
|
|
566
568
|
function parseWorkflow(ctx, error) {
|
|
567
569
|
const workflowTok = ctx.peek();
|
|
568
|
-
expectKeyword(ctx, error, KW.WORKFLOW,
|
|
570
|
+
expectKeyword(ctx, error, KW.WORKFLOW, `Expected ${kwq(ctx, KW.WORKFLOW)}`);
|
|
569
571
|
if (!ctx.at(TokenKind.COLON))
|
|
570
|
-
error(
|
|
572
|
+
error(`Expected ':' after ${kwq(ctx, KW.WORKFLOW)}`);
|
|
571
573
|
ctx.next();
|
|
572
574
|
expectNewline(ctx, error);
|
|
573
575
|
if (!ctx.at(TokenKind.INDENT))
|
|
@@ -603,14 +605,14 @@ function parseWorkflow(ctx, error) {
|
|
|
603
605
|
}
|
|
604
606
|
function parseStep(ctx, error) {
|
|
605
607
|
const stepTok = ctx.peek();
|
|
606
|
-
expectKeyword(ctx, error, KW.STEP,
|
|
608
|
+
expectKeyword(ctx, error, KW.STEP, `Expected ${kwq(ctx, KW.STEP)}`);
|
|
607
609
|
const name = parseIdent(ctx, error);
|
|
608
610
|
const dependencies = [];
|
|
609
611
|
if (ctx.isKeyword(KW.DEPENDS)) {
|
|
610
612
|
ctx.nextWord();
|
|
611
|
-
expectKeyword(ctx, error, KW.ON,
|
|
613
|
+
expectKeyword(ctx, error, KW.ON, `Expected ${kwq(ctx, KW.ON)} after ${kwq(ctx, KW.DEPENDS)}`);
|
|
612
614
|
if (!ctx.at(TokenKind.LBRACKET))
|
|
613
|
-
error(
|
|
615
|
+
error(`Expected '[' after '${kw(ctx, KW.DEPENDS)} ${kw(ctx, KW.ON)}'`);
|
|
614
616
|
ctx.next();
|
|
615
617
|
if (!ctx.at(TokenKind.RBRACKET)) {
|
|
616
618
|
while (true) {
|
|
@@ -642,7 +644,7 @@ function parseStep(ctx, error) {
|
|
|
642
644
|
if (ctx.isKeyword(KW.COMPENSATE)) {
|
|
643
645
|
ctx.nextWord();
|
|
644
646
|
if (!ctx.at(TokenKind.COLON))
|
|
645
|
-
error(
|
|
647
|
+
error(`Expected ':' after ${kwq(ctx, KW.COMPENSATE)}`);
|
|
646
648
|
ctx.next();
|
|
647
649
|
expectNewline(ctx, error);
|
|
648
650
|
compensate = parseBlock(ctx, error);
|
|
@@ -654,9 +656,9 @@ function parseStep(ctx, error) {
|
|
|
654
656
|
return step;
|
|
655
657
|
}
|
|
656
658
|
function parseRetryPolicy(ctx, error) {
|
|
657
|
-
expectKeyword(ctx, error, KW.RETRY,
|
|
659
|
+
expectKeyword(ctx, error, KW.RETRY, `Expected ${kwq(ctx, KW.RETRY)}`);
|
|
658
660
|
if (!ctx.at(TokenKind.COLON))
|
|
659
|
-
error(
|
|
661
|
+
error(`Expected ':' after ${kwq(ctx, KW.RETRY)}`);
|
|
660
662
|
ctx.next();
|
|
661
663
|
expectNewline(ctx, error);
|
|
662
664
|
if (!ctx.at(TokenKind.INDENT))
|
|
@@ -669,20 +671,20 @@ function parseRetryPolicy(ctx, error) {
|
|
|
669
671
|
if (ctx.isKeywordSeq(MAX_ATTEMPTS_PARTS)) {
|
|
670
672
|
ctx.nextWords(MAX_ATTEMPTS_PARTS);
|
|
671
673
|
if (!ctx.at(TokenKind.COLON))
|
|
672
|
-
error(
|
|
674
|
+
error(`Expected ':' after ${kwq(ctx, KW.MAX_ATTEMPTS)}`);
|
|
673
675
|
ctx.next();
|
|
674
676
|
if (!ctx.at(TokenKind.INT))
|
|
675
|
-
error(
|
|
677
|
+
error(`Expected integer after ${kwq(ctx, KW.MAX_ATTEMPTS)}`);
|
|
676
678
|
const attempts = ctx.next().value;
|
|
677
679
|
if (attempts <= 0)
|
|
678
|
-
error(
|
|
680
|
+
error(`${kwq(ctx, KW.MAX_ATTEMPTS)} must be greater than zero`);
|
|
679
681
|
maxAttempts = attempts;
|
|
680
682
|
expectPeriodEnd(ctx, error);
|
|
681
683
|
}
|
|
682
684
|
else if (ctx.isKeyword(KW.BACKOFF)) {
|
|
683
685
|
ctx.nextWord();
|
|
684
686
|
if (!ctx.at(TokenKind.COLON))
|
|
685
|
-
error(
|
|
687
|
+
error(`Expected ':' after ${kwq(ctx, KW.BACKOFF)}`);
|
|
686
688
|
ctx.next();
|
|
687
689
|
const modeTok = ctx.nextWord();
|
|
688
690
|
const mode = String(modeTok.value ?? '').toLowerCase();
|
|
@@ -699,15 +701,15 @@ function parseRetryPolicy(ctx, error) {
|
|
|
699
701
|
}
|
|
700
702
|
ctx.next();
|
|
701
703
|
if (maxAttempts === null)
|
|
702
|
-
error(
|
|
704
|
+
error(`Retry section must include ${kwq(ctx, KW.MAX_ATTEMPTS)}`);
|
|
703
705
|
if (backoff === null)
|
|
704
|
-
error(
|
|
706
|
+
error(`Retry section must include ${kwq(ctx, KW.BACKOFF)}`);
|
|
705
707
|
return { maxAttempts, backoff };
|
|
706
708
|
}
|
|
707
709
|
function parseTimeout(ctx, error) {
|
|
708
|
-
expectKeyword(ctx, error, KW.TIMEOUT,
|
|
710
|
+
expectKeyword(ctx, error, KW.TIMEOUT, `Expected ${kwq(ctx, KW.TIMEOUT)}`);
|
|
709
711
|
if (!ctx.at(TokenKind.COLON))
|
|
710
|
-
error(
|
|
712
|
+
error(`Expected ':' after ${kwq(ctx, KW.TIMEOUT)}`);
|
|
711
713
|
ctx.next();
|
|
712
714
|
if (!ctx.at(TokenKind.INT))
|
|
713
715
|
error('Expected integer timeout value');
|
|
@@ -716,6 +718,8 @@ function parseTimeout(ctx, error) {
|
|
|
716
718
|
if (seconds < 0)
|
|
717
719
|
error('Timeout value must be non-negative');
|
|
718
720
|
if (!(ctx.isKeyword('seconds') || ctx.isKeyword('second'))) {
|
|
721
|
+
// 'seconds' 不做本地化:所有 locale 的词表都没有时间单位的本地拼写,
|
|
722
|
+
// zh/de 作者同样只能写英文 seconds,报错里的 'seconds' 正是作者该写的词。
|
|
719
723
|
error("Timeout must specify time unit 'seconds'");
|
|
720
724
|
}
|
|
721
725
|
ctx.nextWord();
|
|
@@ -739,7 +743,7 @@ function parseCases(ctx, error) {
|
|
|
739
743
|
while (!ctx.at(TokenKind.DEDENT)) {
|
|
740
744
|
if (!ctx.isKeyword(KW.WHEN)) {
|
|
741
745
|
// 改进的错误消息,提示复合模式关系
|
|
742
|
-
error(
|
|
746
|
+
error(`Expected ${kwq(ctx, KW.WHEN, 'When')} (若...为 pattern requires '为' after '若')`);
|
|
743
747
|
}
|
|
744
748
|
const whenTok = ctx.nextWord();
|
|
745
749
|
const pat = parsePattern(ctx, error);
|
|
@@ -816,12 +820,13 @@ function parseIfExpr(ctx, error) {
|
|
|
816
820
|
const cond = parseOr(ctx, error);
|
|
817
821
|
skipInlineThenLayout(ctx);
|
|
818
822
|
if (!ctx.isKeyword(KW.THEN))
|
|
819
|
-
error(
|
|
823
|
+
error(`Expected ${kwq(ctx, KW.THEN)} in if-expression`);
|
|
820
824
|
ctx.nextWord(); // 消费 THEN
|
|
821
825
|
const thenE = parseExpr(ctx, error);
|
|
822
826
|
skipInlineElseLayout(ctx);
|
|
823
827
|
if (!ctx.isKeyword(KW.ELSE) && !ctx.isKeyword(KW.OTHERWISE)) {
|
|
824
|
-
error(
|
|
828
|
+
error(`Expected ${kwKindq(ctx, SemanticTokenKind.OTHERWISE, 'else')} in if-expression ` +
|
|
829
|
+
`(${kwKind(ctx, SemanticTokenKind.OTHERWISE, 'else')} is mandatory for expression-level if)`);
|
|
825
830
|
}
|
|
826
831
|
ctx.nextWord(); // 消费 ELSE / OTHERWISE
|
|
827
832
|
const elseE = parseExpr(ctx, error);
|
|
@@ -1293,7 +1298,7 @@ function parseApplyOrPrimary(ctx, error) {
|
|
|
1293
1298
|
if (ctx.isKeyword(KW.APPLY) && applyLooksLikeCall(ctx)) {
|
|
1294
1299
|
const applyTok = ctx.nextWord();
|
|
1295
1300
|
const fn = parseCallTargetName(ctx, error);
|
|
1296
|
-
expectKeyword(ctx, error, KW.TO_WORD,
|
|
1301
|
+
expectKeyword(ctx, error, KW.TO_WORD, `Use '${kw(ctx, KW.APPLY)} <fn> ${kw(ctx, KW.TO_WORD)} <arg>' (expected ${kwq(ctx, KW.TO_WORD)}).`);
|
|
1297
1302
|
const arg = parseExpr(ctx, error);
|
|
1298
1303
|
const call = Node.Call(fn, [arg]);
|
|
1299
1304
|
assignSpan(call, spanFromSources(applyTok, arg));
|
|
@@ -1332,7 +1337,7 @@ function applyLooksLikeCall(ctx) {
|
|
|
1332
1337
|
function parseCallTargetName(ctx, error) {
|
|
1333
1338
|
const startTok = ctx.peek();
|
|
1334
1339
|
if (!ctx.at(TokenKind.IDENT) && !ctx.at(TokenKind.TYPE_IDENT)) {
|
|
1335
|
-
error(
|
|
1340
|
+
error(`Expected a function name after ${kwq(ctx, KW.APPLY)}.`);
|
|
1336
1341
|
}
|
|
1337
1342
|
const consumed = [ctx.peek()];
|
|
1338
1343
|
let full = ctx.at(TokenKind.IDENT) ? parseIdent(ctx, error) : ctx.next().value;
|
|
@@ -1402,7 +1407,7 @@ function operatorWordBeforeParen(ctx, english) {
|
|
|
1402
1407
|
function parseOperatorWordCall(ctx, error, word, english) {
|
|
1403
1408
|
const symbol = english ? null : OPERATOR_WORD_SYMBOLS.get(word);
|
|
1404
1409
|
if (!symbol) {
|
|
1405
|
-
error(`运算符词
|
|
1410
|
+
error(`运算符词 ${kwq(ctx, word)} 不能用作前缀调用;只有符号运算符 ${PREFIX_SYMBOL_LIST} 可以写成 op(a, b)`);
|
|
1406
1411
|
}
|
|
1407
1412
|
return parsePrefixOperatorCall(ctx, error, symbol, kwParts(word).length);
|
|
1408
1413
|
}
|
|
@@ -1434,7 +1439,7 @@ function parsePrimary(ctx, error) {
|
|
|
1434
1439
|
const functionTok = ctx.nextWord(); // 'function'
|
|
1435
1440
|
const params = parseParamList(ctx, error);
|
|
1436
1441
|
expectCommaOr(ctx);
|
|
1437
|
-
expectKeyword(ctx, error, KW.PRODUCE,
|
|
1442
|
+
expectKeyword(ctx, error, KW.PRODUCE, `Expected ${kwq(ctx, KW.PRODUCE)} and return type`);
|
|
1438
1443
|
let retType;
|
|
1439
1444
|
if (ctx.at(TokenKind.COLON)) {
|
|
1440
1445
|
retType = Node.TypeName('Unknown');
|
|
@@ -1658,11 +1663,11 @@ function parsePrimary(ctx, error) {
|
|
|
1658
1663
|
const nameTok = ctx.peek();
|
|
1659
1664
|
const name = parseIdent(ctx, error);
|
|
1660
1665
|
if (!ctx.isKeyword(KW.SET))
|
|
1661
|
-
error(
|
|
1666
|
+
error(`Expected '${kw(ctx, KW.SET)} ${kw(ctx, KW.TO_WORD)}' in construction`);
|
|
1662
1667
|
const equalsTok = ctx.peek();
|
|
1663
1668
|
ctx.nextWord();
|
|
1664
1669
|
if (!ctx.isKeyword(KW.TO_WORD))
|
|
1665
|
-
error(
|
|
1670
|
+
error(`Expected ${kwq(ctx, KW.TO_WORD)} after ${kwq(ctx, KW.SET)} in construction`);
|
|
1666
1671
|
ctx.nextWord();
|
|
1667
1672
|
const e = parseExpr(ctx, error);
|
|
1668
1673
|
const fld = {
|
|
@@ -1718,7 +1723,7 @@ function parsePrimary(ctx, error) {
|
|
|
1718
1723
|
// 仅拦截裸类型名(无点链后缀),点链形态(如 SomeType.method(...))不受影响。
|
|
1719
1724
|
if (full === typeName && ctx.declaredRecordTypes.has(typeName)) {
|
|
1720
1725
|
error(`Cannot construct '${typeName}' with positional arguments. ` +
|
|
1721
|
-
`Use named fields instead: '${typeName}
|
|
1726
|
+
`Use named fields instead: '${typeName} ${kw(ctx, KW.WITH)} <field> ${kw(ctx, KW.SET)} ${kw(ctx, KW.TO_WORD)} <value> ${kw(ctx, KW.AND)} ...'`);
|
|
1722
1727
|
}
|
|
1723
1728
|
const args = parseArgList(ctx, error);
|
|
1724
1729
|
const call = Node.Call(target, args);
|
|
@@ -1756,7 +1761,7 @@ function parsePrimary(ctx, error) {
|
|
|
1756
1761
|
// 同 TYPE_IDENT 分支:拦截对已声明类型的位置式构造(无大小写语言里类型名是 IDENT)。
|
|
1757
1762
|
if (full === name && ctx.declaredRecordTypes.has(name)) {
|
|
1758
1763
|
error(`Cannot construct '${name}' with positional arguments. ` +
|
|
1759
|
-
`Use named fields instead: '${name}
|
|
1764
|
+
`Use named fields instead: '${name} ${kw(ctx, KW.WITH)} <field> ${kw(ctx, KW.SET)} ${kw(ctx, KW.TO_WORD)} <value> ${kw(ctx, KW.AND)} ...'`);
|
|
1760
1765
|
}
|
|
1761
1766
|
const args = parseArgList(ctx, error);
|
|
1762
1767
|
const call = Node.Call(target, args);
|