diff --git a/src/grammar/ast.ts b/src/grammar/ast.ts index 180609e96..8669edeaa 100644 --- a/src/grammar/ast.ts +++ b/src/grammar/ast.ts @@ -367,7 +367,7 @@ export type ASTReceiveType = } | { kind: "internal-const-comment"; - comment: ASTId; + comment: ASTLvalueRef[]; } | { kind: "bounce"; @@ -386,7 +386,7 @@ export type ASTReceiveType = } | { kind: "external-const-comment"; - comment: ASTId; + comment: ASTLvalueRef[]; }; export type ASTReceive = { diff --git a/src/grammar/grammar.ohm b/src/grammar/grammar.ohm index bb6afc8e7..282ba5234 100644 --- a/src/grammar/grammar.ohm +++ b/src/grammar/grammar.ohm @@ -85,11 +85,11 @@ Tact { Receiver = receive "(" Parameter? ")" "{" Statement* "}" --regular | receive "(" stringLiteral ")" "{" Statement* "}" --comment - | receive "(" id ")" "{" Statement* "}" --constComment + | receive "(" LValue ")" "{" Statement* "}" --constComment | "bounced" "(" Parameter ")" "{" Statement* "}" --bounced // cannot be a reserved word because there a 'bounced' field in stdlib's 'Context' structure | external "(" Parameter? ")" "{" Statement* "}" --externalRegular | external "(" stringLiteral ")" "{" Statement* "}" --externalComment - | external "(" id ")" "{" Statement* "}" --constExternalComment + | external "(" LValue ")" "{" Statement* "}" --constExternalComment Statement = StatementLet | StatementBlock diff --git a/src/grammar/grammar.ts b/src/grammar/grammar.ts index e4d3c8ea7..68dfa8a47 100644 --- a/src/grammar/grammar.ts +++ b/src/grammar/grammar.ts @@ -353,7 +353,7 @@ semantics.addOperation("astOfItem", { kind: "def_receive", selector: { kind: "internal-const-comment", - comment: comment.astOfExpression(), + comment: comment.astOfLValue(), }, statements: receiverBody.children.map((s) => s.astOfStatement()), ref: createRef(this), @@ -430,7 +430,7 @@ semantics.addOperation("astOfItem", { kind: "def_receive", selector: { kind: "external-const-comment", - comment: comment.astOfExpression(), + comment: comment.astOfLValue(), }, statements: receiverBody.children.map((s) => s.astOfStatement()), ref: createRef(this), diff --git a/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap b/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap index d249ddb64..4c3de2697 100644 --- a/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap +++ b/src/test/e2e-emulated/__snapshots__/const-string-receiver.spec.ts.snap @@ -78,6 +78,12 @@ exports[`constant string receiver should implement const string receiver correct }, "getters": [], "receivers": [ + { + "message": { + "kind": "empty", + }, + "receiver": "internal", + }, { "message": { "kind": "text", @@ -99,6 +105,13 @@ exports[`constant string receiver should implement const string receiver correct }, "receiver": "internal", }, + { + "message": { + "kind": "text", + "text": "string 4", + }, + "receiver": "internal", + }, ], "types": [ { @@ -244,14 +257,14 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "type": "internal", "value": "10", }, }, { "$type": "processed", - "gasUsed": 6689n, + "gasUsed": 6857n, }, { "$type": "sent", @@ -262,10 +275,10 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "to": "@treasure(treasure)", "type": "internal", - "value": "9.992115", + "value": "9.991947", }, ], }, @@ -283,14 +296,14 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "type": "internal", "value": "10", }, }, { "$type": "processed", - "gasUsed": 9300n, + "gasUsed": 9468n, }, { "$type": "sent", @@ -301,10 +314,10 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "to": "@treasure(treasure)", "type": "internal", - "value": "9.989504", + "value": "9.989336", }, ], }, @@ -322,14 +335,14 @@ exports[`constant string receiver should implement const string receiver correct }, "bounce": true, "from": "@treasure(treasure)", - "to": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "type": "internal", "value": "10", }, }, { "$type": "processed", - "gasUsed": 9377n, + "gasUsed": 9581n, }, { "$type": "sent", @@ -340,10 +353,49 @@ exports[`constant string receiver should implement const string receiver correct "type": "text", }, "bounce": true, - "from": "kQDg3ce4axASb2iP16WY4k7nP9uV--zZxPfmGYbm8ZF_YPj4", + "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "to": "@treasure(treasure)", + "type": "internal", + "value": "9.989223", + }, + ], + }, + ], + }, + { + "$seq": 4, + "events": [ + { + "$type": "received", + "message": { + "body": { + "text": "string 4", + "type": "text", + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", + "type": "internal", + "value": "10", + }, + }, + { + "$type": "processed", + "gasUsed": 9730n, + }, + { + "$type": "sent", + "messages": [ + { + "body": { + "text": "string 4", + "type": "text", + }, + "bounce": true, + "from": "kQCjCGWLilNv7PPffKoWdQHPZ-88MekCb9F_U5ddfPTsuH3_", "to": "@treasure(treasure)", "type": "internal", - "value": "9.989427", + "value": "9.989074", }, ], }, diff --git a/src/test/e2e-emulated/const-string-receiver.spec.ts b/src/test/e2e-emulated/const-string-receiver.spec.ts index 1d27bce37..88f5fe823 100644 --- a/src/test/e2e-emulated/const-string-receiver.spec.ts +++ b/src/test/e2e-emulated/const-string-receiver.spec.ts @@ -26,6 +26,7 @@ describe("constant string receiver", () => { await contract.send(treasure, { value: toNano("10") }, "string 1"); await contract.send(treasure, { value: toNano("10") }, "string 2"); await contract.send(treasure, { value: toNano("10") }, "string 3"); + await contract.send(treasure, { value: toNano("10") }, "string 4"); await system.run(); expect(tracker.collect()).toMatchSnapshot(); diff --git a/src/test/e2e-emulated/contracts/const-string-receiver.tact b/src/test/e2e-emulated/contracts/const-string-receiver.tact index 50aa62841..b0f37186b 100644 --- a/src/test/e2e-emulated/contracts/const-string-receiver.tact +++ b/src/test/e2e-emulated/contracts/const-string-receiver.tact @@ -3,6 +3,8 @@ const string2: String = "string 2"; const string3: String = "string 3"; contract ConstStringReceiverTester { + const string4: String = "string 4"; + receive() { } receive("string 1") { @@ -16,4 +18,8 @@ contract ConstStringReceiverTester { receive(string3) { self.reply(string3.asComment()); } + + receive(self.string4) { + self.reply(self.string4.asComment()); + } } \ No newline at end of file diff --git a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap index 9d8add971..8de114d47 100644 --- a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap +++ b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap @@ -50,6 +50,46 @@ Line 24, col 3: " `; +exports[`resolveDescriptors should fail descriptors for contract-duplicate-const-string-receiver 1`] = ` +":20:5: Receive function for string "string 1" already exists +Line 20, col 5: + 19 | +> 20 | receive(string1) { + ^~~~~~~~~~~~~~~~~~ + 21 | +" +`; + +exports[`resolveDescriptors should fail descriptors for contract-duplicate-const-string-receiver2 1`] = ` +":15:5: Receive function for "string 1" already exists +Line 15, col 5: + 14 | +> 15 | receive("string 1") { + ^~~~~~~~~~~~~~~~~~~~~ + 16 | +" +`; + +exports[`resolveDescriptors should fail descriptors for contract-duplicate-const-string-receiver3 1`] = ` +":20:5: Constant "string3" not found +Line 20, col 5: + 19 | +> 20 | receive(string3) { + ^~~~~~~~~~~~~~~~~~ + 21 | +" +`; + +exports[`resolveDescriptors should fail descriptors for contract-duplicate-const-string-receiver4 1`] = ` +":15:5: Receive function for string "string 1" already exists +Line 15, col 5: + 14 | +> 15 | receive(self.string1) { + ^~~~~~~~~~~~~~~~~~~~~~~ + 16 | +" +`; + exports[`resolveDescriptors should fail descriptors for contract-duplicate-external-fallback-receiver 1`] = ` ":20:5: Empty receive function already exists Line 20, col 5: @@ -90,36 +130,6 @@ Line 12, col 23: " `; -exports[`resolveDescriptors should fail descriptors for contract-receiver-const-string-duplicate 1`] = ` -":20:5: Receive function for string "string 1" already exists -Line 20, col 5: - 19 | -> 20 | receive(string1) { - ^~~~~~~~~~~~~~~~~~ - 21 | -" -`; - -exports[`resolveDescriptors should fail descriptors for contract-receiver-const-string-duplicate2 1`] = ` -":15:5: Receive function for "string 1" already exists -Line 15, col 5: - 14 | -> 15 | receive("string 1") { - ^~~~~~~~~~~~~~~~~~~~~ - 16 | -" -`; - -exports[`resolveDescriptors should fail descriptors for contract-receiver-const-string-duplicate3 1`] = ` -":20:5: Constant "string3" not found -Line 20, col 5: - 19 | -> 20 | receive(string3) { - ^~~~~~~~~~~~~~~~~~ - 21 | -" -`; - exports[`resolveDescriptors should fail descriptors for contract-receiver-int 1`] = ` ":13:3: Receive function can only accept message, Slice or String Line 13, col 3: diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index c784659c3..344250532 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -1033,10 +1033,25 @@ export function resolveDescriptors(ctx: CompilerContext) { const internal = d.selector.kind === "internal-const-comment"; - const commentId = d.selector.comment.value; - const commentConstant = - s.constants.find((v) => v.name === commentId) ?? - staticConstants.get(commentId); + if (d.selector.comment.length > 2) { + // TEMPORARY + // to be reworked after #284 and #400 are resolved + throwSyntaxError( + "Invalid comment receiver selector", + d.ref, + ); + } + + const isSelf = + d.selector.comment.length === 2 && + d.selector.comment[0].name === "self"; + + const commentId = + d.selector.comment[d.selector.comment.length - 1] + .name; + const commentConstant = isSelf + ? s.constants.find((v) => v.name === commentId) + : staticConstants.get(commentId); if (!commentConstant) { throwSyntaxError( diff --git a/src/types/test-failed/contract-receiver-const-string-duplicate.tact b/src/types/test-failed/contract-duplicate-const-string-receiver.tact similarity index 100% rename from src/types/test-failed/contract-receiver-const-string-duplicate.tact rename to src/types/test-failed/contract-duplicate-const-string-receiver.tact diff --git a/src/types/test-failed/contract-receiver-const-string-duplicate2.tact b/src/types/test-failed/contract-duplicate-const-string-receiver2.tact similarity index 100% rename from src/types/test-failed/contract-receiver-const-string-duplicate2.tact rename to src/types/test-failed/contract-duplicate-const-string-receiver2.tact diff --git a/src/types/test-failed/contract-receiver-const-string-duplicate3.tact b/src/types/test-failed/contract-duplicate-const-string-receiver3.tact similarity index 100% rename from src/types/test-failed/contract-receiver-const-string-duplicate3.tact rename to src/types/test-failed/contract-duplicate-const-string-receiver3.tact diff --git a/src/types/test-failed/contract-duplicate-const-string-receiver4.tact b/src/types/test-failed/contract-duplicate-const-string-receiver4.tact new file mode 100644 index 000000000..045c7562c --- /dev/null +++ b/src/types/test-failed/contract-duplicate-const-string-receiver4.tact @@ -0,0 +1,18 @@ +primitive Int; +primitive String; + +trait BaseTrait { + +} + +contract Main { + const string1: String = "string 1"; + + receive("string 1") { + + } + + receive(self.string1) { + + } +} \ No newline at end of file