@harmoniclabs/pebble 0.1.10 → 0.2.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/dist/IR/IRNodes/IRConst.js +14 -3
- package/dist/IR/IRNodes/IRNative/index.js +5 -1
- package/dist/IR/toUPLC/CompilerOptions.d.ts +22 -7
- package/dist/IR/toUPLC/CompilerOptions.js +5 -1
- package/dist/IR/tree_utils/bytesToHex.d.ts +8 -0
- package/dist/IR/tree_utils/bytesToHex.js +69 -0
- package/dist/ast/nodes/expr/functions/FuncExpr.d.ts +16 -2
- package/dist/ast/nodes/expr/functions/FuncExpr.js +17 -0
- package/dist/ast/nodes/expr/litteral/LitteralExpr.d.ts +2 -1
- package/dist/ast/nodes/expr/litteral/LitteralExpr.js +2 -0
- package/dist/ast/nodes/expr/litteral/TemplateStrExpr.d.ts +30 -0
- package/dist/ast/nodes/expr/litteral/TemplateStrExpr.js +35 -0
- package/dist/ast/nodes/statements/ExportStmt.d.ts +3 -3
- package/dist/ast/nodes/statements/PebbleStmt.d.ts +4 -3
- package/dist/ast/nodes/statements/PebbleStmt.js +6 -2
- package/dist/ast/nodes/statements/TestParam.d.ts +18 -0
- package/dist/ast/nodes/statements/TestParam.js +18 -0
- package/dist/ast/nodes/statements/TestStmt.d.ts +5 -3
- package/dist/ast/nodes/statements/TestStmt.js +3 -1
- package/dist/ast/nodes/statements/UsingStmt.d.ts +32 -2
- package/dist/ast/nodes/statements/UsingStmt.js +39 -3
- package/dist/ast/nodes/statements/declarations/NamespaceDecl.d.ts +21 -0
- package/dist/ast/nodes/statements/declarations/NamespaceDecl.js +31 -0
- package/dist/compiler/AstCompiler/AstCompiler.d.ts +26 -0
- package/dist/compiler/AstCompiler/AstCompiler.js +203 -3
- package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +13 -2
- package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +97 -6
- package/dist/compiler/AstCompiler/internal/exprs/_compileFuncExpr.js +12 -5
- package/dist/compiler/AstCompiler/internal/exprs/_compileLitteralExpr.js +59 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.d.ts +2 -3
- package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +28 -0
- package/dist/compiler/AstCompiler/internal/exprs/_compileVarAccessExpr.js +2 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileStatement.js +4 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.d.ts +15 -1
- package/dist/compiler/AstCompiler/internal/statements/_compileTestStmt.js +70 -30
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.d.ts +11 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingAliasStmt.js +26 -0
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.d.ts +9 -4
- package/dist/compiler/AstCompiler/internal/statements/_compileUsingStmt.js +51 -10
- package/dist/compiler/AstCompiler/internal/types/_compileDataEncodedConcreteType.js +21 -2
- package/dist/compiler/AstCompiler/internal/types/_compileSopEncodedConcreteType.js +17 -2
- package/dist/compiler/AstCompiler/scope/AstScope.d.ts +70 -1
- package/dist/compiler/AstCompiler/scope/AstScope.js +91 -0
- package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +25 -1
- package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.d.ts +36 -0
- package/dist/compiler/AstCompiler/utils/monomorphizeGeneric.js +123 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.d.ts +28 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespaceChain.js +95 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespacePath.d.ts +37 -0
- package/dist/compiler/AstCompiler/utils/resolveNamespacePath.js +93 -0
- package/dist/compiler/Compiler.d.ts +9 -1
- package/dist/compiler/Compiler.js +204 -9
- package/dist/compiler/TirCompiler/expressify/expressifyVars.js +26 -7
- package/dist/compiler/test/TestResult.d.ts +38 -0
- package/dist/compiler/test/TestResult.js +6 -0
- package/dist/compiler/test/fuzz/PRNG.d.ts +26 -0
- package/dist/compiler/test/fuzz/PRNG.js +59 -0
- package/dist/compiler/tir/expressions/TirExpr.d.ts +2 -1
- package/dist/compiler/tir/expressions/TirExpr.js +2 -0
- package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +17 -0
- package/dist/compiler/tir/expressions/TirNativeFunc.js +53 -106
- package/dist/compiler/tir/expressions/TirShowExpr.d.ts +52 -0
- package/dist/compiler/tir/expressions/TirShowExpr.js +199 -0
- package/dist/compiler/tir/expressions/TirTraceExpr.js +11 -7
- package/dist/compiler/tir/program/TypedProgram.d.ts +101 -0
- package/dist/compiler/tir/program/TypedProgram.js +43 -0
- package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.d.ts +17 -0
- package/dist/compiler/tir/program/stdScope/populateBuiltinInterfaces.js +70 -0
- package/dist/compiler/tir/program/stdScope/populateStdNamespace.d.ts +22 -0
- package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +574 -0
- package/dist/compiler/tir/program/stdScope/stdScope.d.ts +1 -0
- package/dist/compiler/tir/program/stdScope/stdScope.js +1 -1
- package/dist/compiler/tir/statements/TirStmt.js +0 -1
- package/dist/compiler/tir/statements/TirTestStmt.d.ts +46 -0
- package/dist/compiler/tir/statements/TirTestStmt.js +35 -0
- package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +50 -1
- package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +53 -1
- package/dist/compiler/tir/types/TirType.js +3 -1
- package/dist/compiler/tir/types/utils/canAssignTo.js +8 -1
- package/dist/compiler/tir/types/utils/inferTypeArgs.d.ts +19 -0
- package/dist/compiler/tir/types/utils/inferTypeArgs.js +79 -0
- package/dist/compiler/tir/types/utils/substituteTypeParams.d.ts +9 -0
- package/dist/compiler/tir/types/utils/substituteTypeParams.js +62 -0
- package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
- package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/parser/Parser.d.ts +73 -3
- package/dist/parser/Parser.js +333 -33
- package/dist/tokenizer/Token.d.ts +105 -102
- package/dist/tokenizer/Token.js +110 -109
- package/dist/tokenizer/utils/tokenFromKeyword.js +9 -6
- package/dist/utils/semverSatisfies.d.ts +1 -0
- package/dist/utils/semverSatisfies.js +161 -0
- package/dist/version.generated.d.ts +1 -0
- package/dist/version.generated.js +2 -0
- package/package.json +3 -2
package/dist/parser/Parser.js
CHANGED
|
@@ -21,13 +21,14 @@ import { LitThisExpr } from "../ast/nodes/expr/litteral/LitThisExpr.js";
|
|
|
21
21
|
import { LitTrueExpr } from "../ast/nodes/expr/litteral/LitTrueExpr.js";
|
|
22
22
|
import { ParentesizedExpr } from "../ast/nodes/expr/ParentesizedExpr.js";
|
|
23
23
|
import { ArrowKind } from "../ast/nodes/expr/functions/ArrowKind.js";
|
|
24
|
-
import { FuncExpr } from "../ast/nodes/expr/functions/FuncExpr.js";
|
|
24
|
+
import { FuncExpr, TypeParamDecl } from "../ast/nodes/expr/functions/FuncExpr.js";
|
|
25
25
|
import { AstBooleanType, AstBytesType, AstListType, AstIntType, AstNativeOptionalType, AstVoidType, AstLinearMapType, AstFuncType } from "../ast/nodes/types/AstNativeTypeExpr.js";
|
|
26
26
|
import { AstNamedTypeExpr } from "../ast/nodes/types/AstNamedTypeExpr.js";
|
|
27
27
|
import { LitArrExpr } from "../ast/nodes/expr/litteral/LitArrExpr.js";
|
|
28
28
|
import { LitNamedObjExpr } from "../ast/nodes/expr/litteral/LitNamedObjExpr.js";
|
|
29
29
|
import { LitObjExpr } from "../ast/nodes/expr/litteral/LitObjExpr.js";
|
|
30
30
|
import { LitStrExpr } from "../ast/nodes/expr/litteral/LitStrExpr.js";
|
|
31
|
+
import { TemplateStrExpr } from "../ast/nodes/expr/litteral/TemplateStrExpr.js";
|
|
31
32
|
import { LitIntExpr } from "../ast/nodes/expr/litteral/LitIntExpr.js";
|
|
32
33
|
import { LitHexBytesExpr } from "../ast/nodes/expr/litteral/LitHexBytesExpr.js";
|
|
33
34
|
import { CallExpr } from "../ast/nodes/expr/functions/CallExpr.js";
|
|
@@ -44,6 +45,7 @@ import { FailStmt } from "../ast/nodes/statements/FailStmt.js";
|
|
|
44
45
|
import { TraceStmt } from "../ast/nodes/statements/TraceStmt.js";
|
|
45
46
|
import { AssertStmt } from "../ast/nodes/statements/AssertStmt.js";
|
|
46
47
|
import { TestStmt } from "../ast/nodes/statements/TestStmt.js";
|
|
48
|
+
import { TestParam } from "../ast/nodes/statements/TestParam.js";
|
|
47
49
|
import { MatchStmt, MatchStmtCase, MatchStmtElseCase } from "../ast/nodes/statements/MatchStmt.js";
|
|
48
50
|
import { WhileStmt } from "../ast/nodes/statements/WhileStmt.js";
|
|
49
51
|
import { CaseExpr, CaseExprMatcher, CaseWildcardMatcher } from "../ast/nodes/expr/CaseExpr.js";
|
|
@@ -65,7 +67,8 @@ import { makePropAccessExpr } from "../ast/nodes/expr/PropAccessExpr.js";
|
|
|
65
67
|
import { makeBinaryExpr } from "../ast/nodes/expr/binary/BinaryExpr.js";
|
|
66
68
|
import { isAssignmentStmt, makeAssignmentStmt } from "../ast/nodes/statements/AssignmentStmt.js";
|
|
67
69
|
import { hoistStatementsInplace } from "./hoistStatementsInplace.js";
|
|
68
|
-
import { UsingStmt, UsingStmtDeclaredConstructor } from "../ast/nodes/statements/UsingStmt.js";
|
|
70
|
+
import { UsingAliasStmt, UsingPath, UsingStmt, UsingStmtDeclaredConstructor } from "../ast/nodes/statements/UsingStmt.js";
|
|
71
|
+
import { NamespaceDecl, NamespaceMember } from "../ast/nodes/statements/declarations/NamespaceDecl.js";
|
|
69
72
|
import { IncrStmt } from "../ast/nodes/statements/IncrStmt.js";
|
|
70
73
|
import { DecrStmt } from "../ast/nodes/statements/DecrStmt.js";
|
|
71
74
|
import { ExportStmt } from "../ast/nodes/statements/ExportStmt.js";
|
|
@@ -151,9 +154,15 @@ export class Parser extends DiagnosticEmitter {
|
|
|
151
154
|
break;
|
|
152
155
|
}
|
|
153
156
|
case Token.Using: {
|
|
157
|
+
tn.next(); // skip `using`
|
|
154
158
|
statement = this.parseUsingDecl();
|
|
155
159
|
break;
|
|
156
160
|
}
|
|
161
|
+
case Token.Namespace: {
|
|
162
|
+
tn.next(); // skip `namespace`
|
|
163
|
+
statement = this.parseNamespaceDecl(startPos);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
157
166
|
case Token.Enum: {
|
|
158
167
|
tn.next();
|
|
159
168
|
statement = this.parseEnum(flags, startPos);
|
|
@@ -374,8 +383,19 @@ export class Parser extends DiagnosticEmitter {
|
|
|
374
383
|
parseUsingDecl() {
|
|
375
384
|
const tn = this.tn;
|
|
376
385
|
const startPos = tn.tokenPos;
|
|
377
|
-
|
|
378
|
-
|
|
386
|
+
// alias form: `using <ident> = <NamespacePath>;`
|
|
387
|
+
if (!tn.skip(Token.OpenBrace)) {
|
|
388
|
+
if (!tn.skipIdentifier())
|
|
389
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
|
390
|
+
const alias = new Identifier(tn.readIdentifier(), tn.range());
|
|
391
|
+
if (!tn.skip(Token.Equals))
|
|
392
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "=");
|
|
393
|
+
const path = this.parseUsingPath();
|
|
394
|
+
if (!path)
|
|
395
|
+
return undefined;
|
|
396
|
+
return new UsingAliasStmt(alias, path, tn.range(startPos, tn.pos));
|
|
397
|
+
}
|
|
398
|
+
// destructure form: `using { a, b: c } = <rhs>;`
|
|
379
399
|
const members = new Array();
|
|
380
400
|
while (!tn.skip(Token.CloseBrace)) {
|
|
381
401
|
const thisStartPos = tn.tokenPos;
|
|
@@ -397,10 +417,169 @@ export class Parser extends DiagnosticEmitter {
|
|
|
397
417
|
}
|
|
398
418
|
if (!tn.skip(Token.Equals))
|
|
399
419
|
return this.error(DiagnosticCode._0_expected, tn.range(), "=");
|
|
400
|
-
const
|
|
401
|
-
if (!
|
|
420
|
+
const rhs = this.parseUsingRhs();
|
|
421
|
+
if (!rhs)
|
|
402
422
|
return undefined;
|
|
403
|
-
return new UsingStmt(members,
|
|
423
|
+
return new UsingStmt(members, rhs, tn.range(startPos, tn.pos));
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* parse a dotted chain of identifiers: `A`, `A.B`, `A.B.C`, ...
|
|
427
|
+
* used for namespace paths on the RHS of `using` statements.
|
|
428
|
+
*/
|
|
429
|
+
parseUsingPath() {
|
|
430
|
+
const tn = this.tn;
|
|
431
|
+
const startPos = tn.tokenPos;
|
|
432
|
+
if (!tn.skipIdentifier())
|
|
433
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
434
|
+
const segments = [
|
|
435
|
+
new Identifier(tn.readIdentifier(), tn.range())
|
|
436
|
+
];
|
|
437
|
+
while (tn.skip(Token.Dot)) {
|
|
438
|
+
if (!tn.skipIdentifier())
|
|
439
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
440
|
+
segments.push(new Identifier(tn.readIdentifier(), tn.range()));
|
|
441
|
+
}
|
|
442
|
+
return new UsingPath(segments, tn.range(startPos, tn.pos));
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* parse the RHS of `using { ... } = <rhs>;`:
|
|
446
|
+
* - if it begins with a native type keyword (or a generic struct
|
|
447
|
+
* with type args), it's parsed as `AstTypeExpr` (legacy
|
|
448
|
+
* struct-destructure behavior)
|
|
449
|
+
* - if it's a single identifier followed by `<`, it's also parsed as
|
|
450
|
+
* a generic type expression
|
|
451
|
+
* - otherwise, it's parsed as a dotted `UsingPath`
|
|
452
|
+
* (a namespace path; the compiler decides whether it's a struct
|
|
453
|
+
* type or a namespace based on what the head identifier resolves to)
|
|
454
|
+
*/
|
|
455
|
+
parseUsingRhs() {
|
|
456
|
+
const tn = this.tn;
|
|
457
|
+
const next = tn.peek();
|
|
458
|
+
// native type keywords always go through parseTypeExpr
|
|
459
|
+
if (next === Token.Void
|
|
460
|
+
|| next === Token.Boolean
|
|
461
|
+
|| next === Token.Int
|
|
462
|
+
|| next === Token.Bytes
|
|
463
|
+
|| next === Token.Optional
|
|
464
|
+
|| next === Token.List
|
|
465
|
+
|| next === Token.LinearMap) {
|
|
466
|
+
const t = this.parseTypeExpr();
|
|
467
|
+
if (!t)
|
|
468
|
+
return undefined;
|
|
469
|
+
return t;
|
|
470
|
+
}
|
|
471
|
+
const path = this.parseUsingPath();
|
|
472
|
+
if (!path)
|
|
473
|
+
return undefined;
|
|
474
|
+
// single-segment path followed by `<...>` → generic struct type expression
|
|
475
|
+
if (path.segments.length === 1
|
|
476
|
+
&& tn.peek() === Token.LessThan) {
|
|
477
|
+
tn.next(); // consume `<`
|
|
478
|
+
const tyArgs = [];
|
|
479
|
+
do {
|
|
480
|
+
const ty = this.parseTypeExpr();
|
|
481
|
+
if (!ty)
|
|
482
|
+
return undefined;
|
|
483
|
+
tyArgs.push(ty);
|
|
484
|
+
} while (tn.skip(Token.Comma));
|
|
485
|
+
if (!tn.skip(Token.GreaterThan))
|
|
486
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), ">");
|
|
487
|
+
return new AstNamedTypeExpr(path.segments[0], tyArgs, tn.range(path.range.start, tn.pos));
|
|
488
|
+
}
|
|
489
|
+
return path;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* parse a namespace body: `{ (private? <member-decl>)* }`
|
|
493
|
+
*
|
|
494
|
+
* called with `namespace` already consumed; `startPos` is the position
|
|
495
|
+
* of the `namespace` keyword.
|
|
496
|
+
*/
|
|
497
|
+
parseNamespaceDecl(startPos) {
|
|
498
|
+
const tn = this.tn;
|
|
499
|
+
if (!tn.skipIdentifier())
|
|
500
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
501
|
+
const name = new Identifier(tn.readIdentifier(), tn.range());
|
|
502
|
+
if (!tn.skip(Token.OpenBrace))
|
|
503
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
|
504
|
+
const members = [];
|
|
505
|
+
while (!tn.skip(Token.CloseBrace)) {
|
|
506
|
+
tn.skip(Token.Semicolon);
|
|
507
|
+
if (tn.skip(Token.CloseBrace))
|
|
508
|
+
break;
|
|
509
|
+
const memberStartPos = tn.tokenPos;
|
|
510
|
+
const isPrivate = tn.skip(Token.Private);
|
|
511
|
+
const member = this.parseNamespaceMember();
|
|
512
|
+
if (!member)
|
|
513
|
+
return undefined;
|
|
514
|
+
members.push(new NamespaceMember(isPrivate, member, tn.range(memberStartPos, tn.pos)));
|
|
515
|
+
tn.skip(Token.Semicolon);
|
|
516
|
+
}
|
|
517
|
+
return new NamespaceDecl(name, members, tn.range(startPos, tn.pos));
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* parse a single namespace body member. delegates to the relevant
|
|
521
|
+
* top-level-style parser based on the next token, but rejects
|
|
522
|
+
* declarations that aren't allowed inside a namespace body
|
|
523
|
+
* (no `export`, no `import`, no `using`, no `contract`, no `test`).
|
|
524
|
+
*/
|
|
525
|
+
parseNamespaceMember() {
|
|
526
|
+
const tn = this.tn;
|
|
527
|
+
const startPos = tn.tokenPos;
|
|
528
|
+
const flags = CommonFlags.None;
|
|
529
|
+
const first = tn.peek();
|
|
530
|
+
switch (first) {
|
|
531
|
+
case Token.Namespace: {
|
|
532
|
+
tn.next();
|
|
533
|
+
return this.parseNamespaceDecl(startPos);
|
|
534
|
+
}
|
|
535
|
+
case Token.Function: {
|
|
536
|
+
tn.next();
|
|
537
|
+
return this.parseFuncDecl(flags, startPos);
|
|
538
|
+
}
|
|
539
|
+
case Token.Interface: {
|
|
540
|
+
tn.next();
|
|
541
|
+
return this.parseInterface(flags, startPos);
|
|
542
|
+
}
|
|
543
|
+
case Token.Var:
|
|
544
|
+
case Token.Let:
|
|
545
|
+
case Token.Const: {
|
|
546
|
+
tn.next();
|
|
547
|
+
return this.parseVarStmt(first === Token.Const ? CommonFlags.Const : CommonFlags.Let, startPos);
|
|
548
|
+
}
|
|
549
|
+
case Token.Enum: {
|
|
550
|
+
tn.next();
|
|
551
|
+
return this.parseEnum(flags, startPos);
|
|
552
|
+
}
|
|
553
|
+
case Token.Struct: {
|
|
554
|
+
tn.next();
|
|
555
|
+
return this.parseStruct(StructDeclAstFlags.none, flags, startPos);
|
|
556
|
+
}
|
|
557
|
+
case Token.Data: {
|
|
558
|
+
tn.next();
|
|
559
|
+
if (tn.peek() !== Token.Struct)
|
|
560
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "struct");
|
|
561
|
+
tn.next();
|
|
562
|
+
return this.parseStruct(StructDeclAstFlags.onlyDataEncoding, flags, startPos);
|
|
563
|
+
}
|
|
564
|
+
case Token.Runtime: {
|
|
565
|
+
tn.next();
|
|
566
|
+
if (tn.peek() !== Token.Struct)
|
|
567
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "struct");
|
|
568
|
+
tn.next();
|
|
569
|
+
return this.parseStruct(StructDeclAstFlags.onlySopEncoding, flags, startPos);
|
|
570
|
+
}
|
|
571
|
+
case Token.Type: {
|
|
572
|
+
tn.next();
|
|
573
|
+
const stmt = this.parseTypeStmt(flags, startPos);
|
|
574
|
+
if (!stmt)
|
|
575
|
+
return undefined;
|
|
576
|
+
if (!(stmt instanceof TypeAliasDecl))
|
|
577
|
+
return this.error(DiagnosticCode._0_expected, stmt.range, "type alias declaration");
|
|
578
|
+
return stmt;
|
|
579
|
+
}
|
|
580
|
+
default:
|
|
581
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "namespace member declaration");
|
|
582
|
+
}
|
|
404
583
|
}
|
|
405
584
|
parseTypeParameters() {
|
|
406
585
|
const tn = this.tn;
|
|
@@ -419,6 +598,41 @@ export class Parser extends DiagnosticEmitter {
|
|
|
419
598
|
}
|
|
420
599
|
return typeParams;
|
|
421
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Parses a function's type-parameter list with optional `implements`
|
|
603
|
+
* interface constraints:
|
|
604
|
+
* `<T, U implements ToData, V implements Foo>`
|
|
605
|
+
*
|
|
606
|
+
* Returns `TypeParamDecl[]` so the compiler can read each param's
|
|
607
|
+
* optional constraint at template-registration time. Struct/interface
|
|
608
|
+
* decls keep using the simpler {@link parseTypeParameters} which
|
|
609
|
+
* returns bare `Identifier[]`.
|
|
610
|
+
*/
|
|
611
|
+
parseFuncTypeParameters() {
|
|
612
|
+
const tn = this.tn;
|
|
613
|
+
// at '<': TypeParamDecl (',' TypeParamDecl)* '>'
|
|
614
|
+
const typeParams = new Array();
|
|
615
|
+
while (!tn.skip(Token.GreaterThan)) {
|
|
616
|
+
const startPos = tn.tokenPos;
|
|
617
|
+
if (!tn.skipIdentifier())
|
|
618
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
619
|
+
const name = new Identifier(tn.readIdentifier(), tn.range());
|
|
620
|
+
let constraint = undefined;
|
|
621
|
+
if (tn.skip(Token.Implements)) {
|
|
622
|
+
constraint = this.parseTypeExpr();
|
|
623
|
+
if (!constraint)
|
|
624
|
+
return undefined;
|
|
625
|
+
}
|
|
626
|
+
typeParams.push(new TypeParamDecl(name, constraint, tn.range(startPos, tn.pos)));
|
|
627
|
+
if (tn.skip(Token.Comma))
|
|
628
|
+
continue;
|
|
629
|
+
if (tn.skip(Token.GreaterThan))
|
|
630
|
+
break;
|
|
631
|
+
else
|
|
632
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), ">");
|
|
633
|
+
}
|
|
634
|
+
return typeParams;
|
|
635
|
+
}
|
|
422
636
|
parseTypeArguments() {
|
|
423
637
|
const tn = this.tn;
|
|
424
638
|
// at '<': TypeParameter (',' TypeParameter)* '>'
|
|
@@ -537,7 +751,11 @@ export class Parser extends DiagnosticEmitter {
|
|
|
537
751
|
const body = this.parseBlockStmt();
|
|
538
752
|
if (!body)
|
|
539
753
|
return undefined;
|
|
540
|
-
members.push(new InterfaceMethodImpl(methodName,
|
|
754
|
+
members.push(new InterfaceMethodImpl(methodName,
|
|
755
|
+
// InterfaceMethodImpl still uses bare Identifier[];
|
|
756
|
+
// strip any constraint clauses (method-decl constraints
|
|
757
|
+
// would be a separate feature).
|
|
758
|
+
typeParams?.map(p => p.name) ?? [], sig, body, tn.range(startPos, tn.pos)));
|
|
541
759
|
}
|
|
542
760
|
tn.skip(Token.Semicolon); // if any
|
|
543
761
|
return new TypeImplementsStmt(typeId, interfaceType, members, tn.range());
|
|
@@ -747,7 +965,7 @@ export class Parser extends DiagnosticEmitter {
|
|
|
747
965
|
let typeParams = undefined;
|
|
748
966
|
if (tn.skip(Token.LessThan)) {
|
|
749
967
|
sigStart = tn.tokenPos;
|
|
750
|
-
typeParams = this.
|
|
968
|
+
typeParams = this.parseFuncTypeParameters();
|
|
751
969
|
if (!typeParams || typeParams.length === 0)
|
|
752
970
|
return undefined;
|
|
753
971
|
// flags |= CommonFlags.Generic;
|
|
@@ -776,15 +994,11 @@ export class Parser extends DiagnosticEmitter {
|
|
|
776
994
|
const namedSig = this.parseNamedFuncSig(flags, startPos, defaultReturnType);
|
|
777
995
|
if (!namedSig)
|
|
778
996
|
return undefined;
|
|
779
|
-
const [name,
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
if (!(arg instanceof AstNamedTypeExpr))
|
|
785
|
-
return this.error(DiagnosticCode.Type_parameters_must_be_identifiers, arg.range);
|
|
786
|
-
typeParams[i] = arg.name;
|
|
787
|
-
}
|
|
997
|
+
const [name, typeParamsRaw, sig] = namedSig;
|
|
998
|
+
// `parseNamedFuncSig` returns `TypeParamDecl[]` (with optional
|
|
999
|
+
// `implements` constraint per param) — `FuncExpr.typeParams` carries
|
|
1000
|
+
// them through to template registration.
|
|
1001
|
+
const typeParams = typeParamsRaw ?? [];
|
|
788
1002
|
if (!tn.skip(Token.OpenBrace))
|
|
789
1003
|
return this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range());
|
|
790
1004
|
const body = this.parseBlockStmt();
|
|
@@ -792,7 +1006,7 @@ export class Parser extends DiagnosticEmitter {
|
|
|
792
1006
|
return undefined;
|
|
793
1007
|
const endPos = tn.pos;
|
|
794
1008
|
tn.skip(Token.Semicolon); // if any
|
|
795
|
-
const expr = new FuncExpr(name, flags, typeParams
|
|
1009
|
+
const expr = new FuncExpr(name, flags, typeParams, sig, body, ArrowKind.None, tn.range(startPos, endPos));
|
|
796
1010
|
return new FuncDecl(expr);
|
|
797
1011
|
}
|
|
798
1012
|
parseEnum(flags, startPos) {
|
|
@@ -1113,11 +1327,15 @@ export class Parser extends DiagnosticEmitter {
|
|
|
1113
1327
|
switch (token) {
|
|
1114
1328
|
case Token.Void: return new AstVoidType(currRange);
|
|
1115
1329
|
// case Token.True:
|
|
1116
|
-
// case Token.False:
|
|
1330
|
+
// case Token.False:
|
|
1117
1331
|
case Token.Boolean: return new AstBooleanType(currRange);
|
|
1118
1332
|
case Token.Int: return new AstIntType(currRange);
|
|
1119
1333
|
// case Token.Number: return new AstIntType( currRange )
|
|
1120
1334
|
case Token.Bytes: return new AstBytesType(currRange);
|
|
1335
|
+
// `data` is registered in the prelude as a named type; expose it
|
|
1336
|
+
// as a plain `AstNamedTypeExpr` so it can be written in type
|
|
1337
|
+
// position (e.g. `function f(x: data): ...`).
|
|
1338
|
+
case Token.Data: return new AstNamedTypeExpr(new Identifier("data", currRange), [], currRange);
|
|
1121
1339
|
case Token.Optional: {
|
|
1122
1340
|
if (!tn.skip(Token.LessThan)) {
|
|
1123
1341
|
canError && this.error(DiagnosticCode._0_expected, currRange, "Type argument for Optional");
|
|
@@ -1308,7 +1526,10 @@ export class Parser extends DiagnosticEmitter {
|
|
|
1308
1526
|
if (tn.skipIdentifier(IdentifierHandling.Always)) {
|
|
1309
1527
|
prop = new Identifier(tn.readIdentifier(), tn.range());
|
|
1310
1528
|
expr = makePropAccessExpr(token, expr, prop, tn.range(startPos, tn.pos));
|
|
1311
|
-
|
|
1529
|
+
// pass `true` so we attempt `<TypeArgs>` parsing —
|
|
1530
|
+
// generic calls on dotted paths (e.g. `std.x.f<T>(a)`)
|
|
1531
|
+
// need this to consume the type arguments.
|
|
1532
|
+
expr = this.tryParseCallExprOrReturnSame(expr, true);
|
|
1312
1533
|
break;
|
|
1313
1534
|
}
|
|
1314
1535
|
const state = tn.mark();
|
|
@@ -1578,9 +1799,7 @@ export class Parser extends DiagnosticEmitter {
|
|
|
1578
1799
|
return new LitStrExpr(tn.readString(), tn.range(startPos, tn.pos));
|
|
1579
1800
|
}
|
|
1580
1801
|
case Token.StringTemplateLiteralQuote: {
|
|
1581
|
-
this.
|
|
1582
|
-
return undefined;
|
|
1583
|
-
// return this.parseTemplateLiteral();
|
|
1802
|
+
return this.parseTemplateLiteral(startPos);
|
|
1584
1803
|
}
|
|
1585
1804
|
case Token.IntegerLiteral: {
|
|
1586
1805
|
const value = tn.readInteger();
|
|
@@ -2340,17 +2559,63 @@ export class Parser extends DiagnosticEmitter {
|
|
|
2340
2559
|
}
|
|
2341
2560
|
parseTestStatement() {
|
|
2342
2561
|
const tn = this.tn;
|
|
2343
|
-
// at 'test':
|
|
2344
|
-
const
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2562
|
+
// at 'test': Identifier '(' TestParam (',' TestParam)* ')' '{' BlockStmt
|
|
2563
|
+
const startPos = tn.pos;
|
|
2564
|
+
if (!tn.skipIdentifier())
|
|
2565
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
2566
|
+
const testName = new Identifier(tn.readIdentifier(), tn.range());
|
|
2567
|
+
if (!tn.skip(Token.OpenParen))
|
|
2568
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "(");
|
|
2569
|
+
const params = this.parseTestParameters();
|
|
2570
|
+
if (!params)
|
|
2571
|
+
return undefined;
|
|
2572
|
+
if (!tn.skip(Token.OpenBrace))
|
|
2573
|
+
return this.error(DiagnosticCode.Tests_must_be_specified_in_a_block_statement, tn.range());
|
|
2574
|
+
let body = this.parseBlockStmt();
|
|
2351
2575
|
if (!body)
|
|
2352
2576
|
return this.error(DiagnosticCode.Tests_must_be_specified_in_a_block_statement, tn.range());
|
|
2353
|
-
return new TestStmt(testName, body, tn.range(
|
|
2577
|
+
return new TestStmt(testName, params, body, tn.range(startPos, tn.pos));
|
|
2578
|
+
}
|
|
2579
|
+
/**
|
|
2580
|
+
* Parses the parameter list of a `test` declaration:
|
|
2581
|
+
* `( <id>: <type> ('via' <expr>)? (, <id>: <type> ('via' <expr>)? )* )?`
|
|
2582
|
+
*
|
|
2583
|
+
* Assumes the opening `(` has already been consumed by the caller.
|
|
2584
|
+
* Consumes the closing `)` on success.
|
|
2585
|
+
*
|
|
2586
|
+
* `via` is recognised here ONLY — function/method/contract parameter
|
|
2587
|
+
* parsing uses `parseParameters()` which never looks for `Token.Via`.
|
|
2588
|
+
*/
|
|
2589
|
+
parseTestParameters() {
|
|
2590
|
+
const tn = this.tn;
|
|
2591
|
+
const params = [];
|
|
2592
|
+
if (tn.skip(Token.CloseParen))
|
|
2593
|
+
return params;
|
|
2594
|
+
while (true) {
|
|
2595
|
+
const paramStart = tn.pos;
|
|
2596
|
+
if (!tn.skipIdentifier())
|
|
2597
|
+
return this.error(DiagnosticCode.Identifier_expected, tn.range());
|
|
2598
|
+
const name = new Identifier(tn.readIdentifier(), tn.range());
|
|
2599
|
+
if (!tn.skip(Token.Colon))
|
|
2600
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), ":");
|
|
2601
|
+
const type = this.parseTypeExpr();
|
|
2602
|
+
if (!type)
|
|
2603
|
+
return undefined;
|
|
2604
|
+
let viaExpr = undefined;
|
|
2605
|
+
if (tn.skip(Token.Via)) {
|
|
2606
|
+
const expr = this.parseExpr();
|
|
2607
|
+
if (!expr)
|
|
2608
|
+
return undefined;
|
|
2609
|
+
viaExpr = expr;
|
|
2610
|
+
}
|
|
2611
|
+
params.push(new TestParam(name, type, viaExpr, tn.range(paramStart, tn.pos)));
|
|
2612
|
+
if (tn.skip(Token.Comma))
|
|
2613
|
+
continue;
|
|
2614
|
+
if (tn.skip(Token.CloseParen))
|
|
2615
|
+
break;
|
|
2616
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), ")");
|
|
2617
|
+
}
|
|
2618
|
+
return params;
|
|
2354
2619
|
}
|
|
2355
2620
|
parseMatchStatement() {
|
|
2356
2621
|
const tn = this.tn;
|
|
@@ -2416,6 +2681,41 @@ export class Parser extends DiagnosticEmitter {
|
|
|
2416
2681
|
return this.error(DiagnosticCode.Expression_expected, tn.range());
|
|
2417
2682
|
return new TraceStmt(expr, tn.range());
|
|
2418
2683
|
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Parse a backtick-delimited template literal:
|
|
2686
|
+
*
|
|
2687
|
+
* `text ${expr1} more text ${expr2} ...`
|
|
2688
|
+
*
|
|
2689
|
+
* Tokenizer state: on entry, the current token is
|
|
2690
|
+
* `Token.StringTemplateLiteralQuote`; the tokenizer is positioned at
|
|
2691
|
+
* the opening backtick. `readString()` (called with no arg) consumes
|
|
2692
|
+
* the backtick + the first fragment up to `${` or to the closing
|
|
2693
|
+
* backtick; if it stopped at `${` it sets `readingTemplateString = true`
|
|
2694
|
+
* and the parser must consume an expression + `}` and then call
|
|
2695
|
+
* `readString(CharCode.Backtick)` to read the next fragment.
|
|
2696
|
+
*/
|
|
2697
|
+
parseTemplateLiteral(startPos) {
|
|
2698
|
+
const tn = this.tn;
|
|
2699
|
+
const parts = [];
|
|
2700
|
+
const exprs = [];
|
|
2701
|
+
// First fragment — readString advances past the opening backtick.
|
|
2702
|
+
let fragment = tn.readString();
|
|
2703
|
+
parts.push(fragment);
|
|
2704
|
+
while (tn.readingTemplateString) {
|
|
2705
|
+
// Just consumed `${`. Parse the interpolated expression.
|
|
2706
|
+
const interp = this.parseExpr();
|
|
2707
|
+
if (!interp)
|
|
2708
|
+
return this.error(DiagnosticCode.Expression_expected, tn.range());
|
|
2709
|
+
exprs.push(interp);
|
|
2710
|
+
if (!tn.skip(Token.CloseBrace))
|
|
2711
|
+
return this.error(DiagnosticCode._0_expected, tn.range(), "}");
|
|
2712
|
+
// Read the next fragment up to the next `${` or the closing
|
|
2713
|
+
// backtick. `readingTemplateString` is set inside readString.
|
|
2714
|
+
fragment = tn.readString(96 /* CharCode.Backtick */);
|
|
2715
|
+
parts.push(fragment);
|
|
2716
|
+
}
|
|
2717
|
+
return new TemplateStrExpr(parts, exprs, tn.range(startPos, tn.pos));
|
|
2718
|
+
}
|
|
2419
2719
|
parseAssertStatement() {
|
|
2420
2720
|
const tn = this.tn;
|
|
2421
2721
|
const startPos = tn.tokenPos;
|