diff --git a/CHANGELOG.md b/CHANGELOG.md index ab59d49fb..3f63fa978 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Constant evaluator now uses an interpreter: PR [#664](https://github.com/tact-lang/tact/pull/664). This increases the expression simplification capabilities of the constant evaluator to expressions that include: - Calls to user-defined functions. - References to declared global constants. +- Allow omitting semicolons in contract/trait declarations and definitions: PR [#718](https://github.com/tact-lang/tact/pull/718) ### Fixed diff --git a/src/grammar/__snapshots__/grammar.spec.ts.snap b/src/grammar/__snapshots__/grammar.spec.ts.snap index 1fab9f706..f594f6831 100644 --- a/src/grammar/__snapshots__/grammar.spec.ts.snap +++ b/src/grammar/__snapshots__/grammar.spec.ts.snap @@ -863,6 +863,112 @@ exports[`grammar should parse case-35 1`] = ` } `; +exports[`grammar should parse contract-optional-semicolon-for-last-const-def 1`] = ` +{ + "id": 7, + "imports": [], + "items": [ + { + "attributes": [], + "declarations": [ + { + "attributes": [], + "id": 5, + "initializer": { + "id": 4, + "kind": "number", + "loc": 42, + "value": 42n, + }, + "kind": "constant_def", + "loc": const foo: Int = 42, + "name": { + "id": 2, + "kind": "id", + "loc": foo, + "text": "foo", + }, + "type": { + "id": 3, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + ], + "id": 6, + "kind": "contract", + "loc": contract Test { const foo: Int = 42 }, + "name": { + "id": 1, + "kind": "id", + "loc": Test, + "text": "Test", + }, + "traits": [], + }, + ], + "kind": "module", +} +`; + +exports[`grammar should parse contract-optional-semicolon-for-last-storage-var 1`] = ` +{ + "id": 8, + "imports": [], + "items": [ + { + "attributes": [], + "declarations": [ + { + "as": null, + "id": 6, + "initializer": null, + "kind": "field_decl", + "loc": m: map, + "name": { + "id": 2, + "kind": "id", + "loc": m, + "text": "m", + }, + "type": { + "id": 5, + "keyStorageType": null, + "keyType": { + "id": 3, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + "kind": "map_type", + "loc": map, + "valueStorageType": null, + "valueType": { + "id": 4, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + ], + "id": 7, + "kind": "contract", + "loc": contract Test { m: map }, + "name": { + "id": 1, + "kind": "id", + "loc": Test, + "text": "Test", + }, + "traits": [], + }, + ], + "kind": "module", +} +`; + exports[`grammar should parse contract-with-const-override 1`] = ` { "id": 7, @@ -8243,6 +8349,98 @@ exports[`grammar should parse struct-msg-trailing-semicolon 1`] = ` } `; +exports[`grammar should parse trait-optional-semicolon-for-last-const-decl 1`] = ` +{ + "id": 6, + "imports": [], + "items": [ + { + "attributes": [], + "declarations": [ + { + "attributes": [ + { + "loc": abstract, + "type": "abstract", + }, + ], + "id": 4, + "kind": "constant_decl", + "loc": abstract const foo: Int, + "name": { + "id": 2, + "kind": "id", + "loc": foo, + "text": "foo", + }, + "type": { + "id": 3, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + ], + "id": 5, + "kind": "trait", + "loc": trait Test { abstract const foo: Int }, + "name": { + "id": 1, + "kind": "id", + "loc": Test, + "text": "Test", + }, + "traits": [], + }, + ], + "kind": "module", +} +`; + +exports[`grammar should parse trait-optional-semicolon-for-last-fun-decl 1`] = ` +{ + "id": 5, + "imports": [], + "items": [ + { + "attributes": [], + "declarations": [ + { + "attributes": [ + { + "loc": abstract, + "type": "abstract", + }, + ], + "id": 3, + "kind": "function_decl", + "loc": abstract fun foo(), + "name": { + "id": 2, + "kind": "id", + "loc": foo, + "text": "foo", + }, + "params": [], + "return": null, + }, + ], + "id": 4, + "kind": "trait", + "loc": trait Test { abstract fun foo() }, + "name": { + "id": 1, + "kind": "id", + "loc": Test, + "text": "Test", + }, + "traits": [], + }, + ], + "kind": "module", +} +`; + exports[`grammar should parse traits-inheritance-trailing-comma 1`] = ` { "id": 20, diff --git a/src/grammar/grammar.ohm b/src/grammar/grammar.ohm index 17ebb582f..80f151450 100644 --- a/src/grammar/grammar.ohm +++ b/src/grammar/grammar.ohm @@ -36,9 +36,9 @@ Tact { | override --override | abstract --abstract - ConstantDefinition = ConstantAttribute* const id ":" Type "=" Expression ";" + ConstantDefinition = ConstantAttribute* const id ":" Type "=" Expression (";" | &"}") - ConstantDeclaration = ConstantAttribute* const id ":" Type ";" + ConstantDeclaration = ConstantAttribute* const id ":" Type (";" | &"}") StructDecl = "struct" typeId "{" StructFields "}" --regular | "message" ("(" integerLiteral ")")? typeId "{" StructFields "}" --message @@ -65,7 +65,7 @@ Tact { | ConstantDefinition | ConstantDeclaration - StorageVar = FieldDecl ";" + StorageVar = FieldDecl (";" | &"}") ContractInit = "init" Parameters "{" Statement* "}" @@ -81,7 +81,7 @@ Tact { FunctionDefinition = FunctionAttribute* fun id Parameters (":" Type)? "{" Statement* "}" - FunctionDeclaration = FunctionAttribute* fun id Parameters (":" Type)? ";" + FunctionDeclaration = FunctionAttribute* fun id Parameters (":" Type)? (";" | &"}") Parameters = "(" ListOf ","? ")" diff --git a/src/grammar/test/contract-optional-semicolon-for-last-const-def.tact b/src/grammar/test/contract-optional-semicolon-for-last-const-def.tact new file mode 100644 index 000000000..cbf5af7f5 --- /dev/null +++ b/src/grammar/test/contract-optional-semicolon-for-last-const-def.tact @@ -0,0 +1 @@ +contract Test { const foo: Int = 42 } diff --git a/src/grammar/test/contract-optional-semicolon-for-last-storage-var.tact b/src/grammar/test/contract-optional-semicolon-for-last-storage-var.tact new file mode 100644 index 000000000..f191f19f0 --- /dev/null +++ b/src/grammar/test/contract-optional-semicolon-for-last-storage-var.tact @@ -0,0 +1 @@ +contract Test { m: map } diff --git a/src/grammar/test/trait-optional-semicolon-for-last-const-decl.tact b/src/grammar/test/trait-optional-semicolon-for-last-const-decl.tact new file mode 100644 index 000000000..27d875aa7 --- /dev/null +++ b/src/grammar/test/trait-optional-semicolon-for-last-const-decl.tact @@ -0,0 +1 @@ +trait Test { abstract const foo: Int } diff --git a/src/grammar/test/trait-optional-semicolon-for-last-fun-decl.tact b/src/grammar/test/trait-optional-semicolon-for-last-fun-decl.tact new file mode 100644 index 000000000..e688de598 --- /dev/null +++ b/src/grammar/test/trait-optional-semicolon-for-last-fun-decl.tact @@ -0,0 +1 @@ +trait Test { abstract fun foo() }