diff --git a/grammar/README.md b/grammar/README.md
index e2d6ee438c..e7adadb0b2 100644
--- a/grammar/README.md
+++ b/grammar/README.md
@@ -476,7 +476,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs.
whitespace = space / horizontal-tab / newline
```
-Go to: _[horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space), [newline](#user-content-newline)_;
+Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_;
There are two kinds of comments in Leo, as in other languages.
@@ -494,7 +494,7 @@ the ones used in the Java language reference.
comment = block-comment / end-of-line-comment
```
-Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_;
+Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_;
@@ -511,7 +511,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star
/ not-star rest-of-block-comment
```
-Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [not-star](#user-content-not-star), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_;
+Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star](#user-content-not-star)_;
@@ -521,7 +521,7 @@ rest-of-block-comment-after-star = "/"
/ not-star-or-slash rest-of-block-comment
```
-Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_;
+Go to: _[not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_;
@@ -639,7 +639,7 @@ format-string-element = not-double-quote-or-open-brace
/ format-string-container
```
-Go to: _[not-double-quote-or-open-brace](#user-content-not-double-quote-or-open-brace), [not-double-quote-or-close-brace](#user-content-not-double-quote-or-close-brace), [format-string-container](#user-content-format-string-container)_;
+Go to: _[format-string-container](#user-content-format-string-container), [not-double-quote-or-open-brace](#user-content-not-double-quote-or-open-brace), [not-double-quote-or-close-brace](#user-content-not-double-quote-or-close-brace)_;
@@ -764,7 +764,7 @@ atomic-literal = untyped-literal
/ address-literal
```
-Go to: _[product-group-literal](#user-content-product-group-literal), [address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [untyped-literal](#user-content-untyped-literal), [signed-literal](#user-content-signed-literal)_;
+Go to: _[signed-literal](#user-content-signed-literal), [untyped-literal](#user-content-untyped-literal), [boolean-literal](#user-content-boolean-literal), [field-literal](#user-content-field-literal), [unsigned-literal](#user-content-unsigned-literal), [product-group-literal](#user-content-product-group-literal), [address-literal](#user-content-address-literal)_;
After defining the (mostly) alphanumeric tokens above,
@@ -809,7 +809,7 @@ token = keyword
/ symbol
```
-Go to: _[annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol), [atomic-literal](#user-content-atomic-literal), [identifier](#user-content-identifier), [package-name](#user-content-package-name), [keyword](#user-content-keyword), [format-string](#user-content-format-string)_;
+Go to: _[keyword](#user-content-keyword), [format-string](#user-content-format-string), [annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal), [identifier](#user-content-identifier), [package-name](#user-content-package-name), [symbol](#user-content-symbol)_;
@@ -866,7 +866,7 @@ group-type = %s"group"
arithmetic-type = integer-type / field-type / group-type
```
-Go to: _[group-type](#user-content-group-type), [integer-type](#user-content-integer-type), [field-type](#user-content-field-type)_;
+Go to: _[field-type](#user-content-field-type), [integer-type](#user-content-integer-type), [group-type](#user-content-group-type)_;
The arithmetic types, along with the boolean and address types,
@@ -887,7 +887,7 @@ address-type = %s"address"
scalar-type = boolean-type / arithmetic-type / address-type
```
-Go to: _[arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type)_;
+Go to: _[boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type), [arithmetic-type](#user-content-arithmetic-type)_;
Circuit types are denoted by identifiers and the keyword `Self`.
@@ -927,7 +927,7 @@ or a tuple of one or more dimensions.
array-type = "[" type ";" array-dimensions "]"
```
-Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_;
+Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_;
@@ -948,7 +948,7 @@ i.e. types whose values contain (sub-)values
aggregate-type = tuple-type / array-type / circuit-type
```
-Go to: _[array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type)_;
+Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_;
Scalar and aggregate types form all the types.
@@ -994,7 +994,7 @@ A literal is either an atomic one or an affine group literal.
literal = atomic-literal / affine-group-literal
```
-Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_;
+Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_;
The following rule is not directly referenced in the rules for expressions
@@ -1007,7 +1007,7 @@ a group literal is either a product group literal or an affine group literal.
group-literal = product-group-literal / affine-group-literal
```
-Go to: _[affine-group-literal](#user-content-affine-group-literal), [product-group-literal](#user-content-product-group-literal)_;
+Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_;
As often done in grammatical language syntax specifications,
@@ -1036,7 +1036,7 @@ primary-expression = identifier
/ circuit-expression
```
-Go to: _[array-expression](#user-content-array-expression), [tuple-expression](#user-content-tuple-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [literal](#user-content-literal), [expression](#user-content-expression)_;
+Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [tuple-expression](#user-content-tuple-expression), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression)_;
Tuple expressions construct tuples.
@@ -1089,7 +1089,7 @@ Go to: _[expression](#user-content-expression)_;
array-repeat-construction = "[" expression ";" array-dimensions "]"
```
-Go to: _[array-dimensions](#user-content-array-dimensions), [expression](#user-content-expression)_;
+Go to: _[expression](#user-content-expression), [array-dimensions](#user-content-array-dimensions)_;
@@ -1125,7 +1125,7 @@ circuit-construction = circuit-type "{"
"}"
```
-Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_;
+Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_;
@@ -1184,7 +1184,7 @@ postfix-expression = primary-expression
/ postfix-expression "[" [expression] ".." [expression] "]"
```
-Go to: _[natural](#user-content-natural), [identifier](#user-content-identifier), [postfix-expression](#user-content-postfix-expression), [circuit-type](#user-content-circuit-type), [function-arguments](#user-content-function-arguments), [primary-expression](#user-content-primary-expression), [expression](#user-content-expression)_;
+Go to: _[function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [postfix-expression](#user-content-postfix-expression), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [natural](#user-content-natural), [expression](#user-content-expression)_;
Unary operators have the highest operator precedence.
@@ -1236,7 +1236,7 @@ additive-expression = multiplicative-expression
/ additive-expression "-" multiplicative-expression
```
-Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_;
+Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_;
Next in the precedence order are ordering relations.
@@ -1299,7 +1299,7 @@ conditional-expression = disjunctive-expression
":" conditional-expression
```
-Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression)_;
+Go to: _[expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression)_;
Those above are all the expressions.
@@ -1332,7 +1332,7 @@ statement = expression-statement
/ block
```
-Go to: _[loop-statement](#user-content-loop-statement), [conditional-statement](#user-content-conditional-statement), [constant-declaration](#user-content-constant-declaration), [expression-statement](#user-content-expression-statement), [variable-declaration](#user-content-variable-declaration), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [block](#user-content-block)_;
+Go to: _[return-statement](#user-content-return-statement), [variable-declaration](#user-content-variable-declaration), [constant-declaration](#user-content-constant-declaration), [expression-statement](#user-content-expression-statement), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [loop-statement](#user-content-loop-statement)_;
@@ -1373,7 +1373,7 @@ variable-declaration = %s"let" identifier-or-identifiers [ ":" type ] "=" expres
constant-declaration = %s"const" identifier-or-identifiers [ ":" type ] "=" expression ";"
```
-Go to: _[type](#user-content-type), [expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_;
+Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type), [expression](#user-content-expression)_;
@@ -1407,7 +1407,7 @@ conditional-statement = branch
/ branch %s"else" conditional-statement
```
-Go to: _[branch](#user-content-branch), [block](#user-content-block), [conditional-statement](#user-content-conditional-statement)_;
+Go to: _[branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block)_;
A loop statement implicitly defines a loop variable
@@ -1463,7 +1463,7 @@ console-call = assert-call
/ print-call
```
-Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_;
+Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_;
@@ -1522,7 +1522,7 @@ function-declaration = *annotation %s"function" identifier
block
```
-Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [type](#user-content-type)_;
+Go to: _[identifier](#user-content-identifier), [block](#user-content-block), [type](#user-content-type), [function-parameters](#user-content-function-parameters)_;
@@ -1532,7 +1532,7 @@ function-parameters = self-parameter
/ function-inputs
```
-Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter)_;
+Go to: _[self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs)_;
@@ -1553,7 +1553,7 @@ Go to: _[function-input](#user-content-function-input)_;
function-input = [ %s"const" ] identifier ":" type
```
-Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_;
+Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
A circuit member variable declaration consists of an identifier and a type.
@@ -1561,10 +1561,10 @@ A circuit member function declaration consists of a function declaration.
```abnf
-member-variable-declaration = identifier ":" type ( "," / ";" )
+member-variable-declaration = *(identifier ":" type ( "," / ";" )) identifier ":" type ( [ "," ] / ";" )
```
-Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_;
+Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
@@ -1613,7 +1613,7 @@ package-path = "*"
/ "(" package-path *( "," package-path ) [","] ")"
```
-Go to: _[package-name](#user-content-package-name), [identifier](#user-content-identifier), [package-path](#user-content-package-path)_;
+Go to: _[identifier](#user-content-identifier), [package-path](#user-content-package-path), [package-name](#user-content-package-name)_;
Finally, we define a file as a sequence of zero or more declarations.
@@ -1626,7 +1626,7 @@ declaration = import-declaration
/ constant-declaration
```
-Go to: _[circuit-declaration](#user-content-circuit-declaration), [function-declaration](#user-content-function-declaration), [constant-declaration](#user-content-constant-declaration), [import-declaration](#user-content-import-declaration)_;
+Go to: _[import-declaration](#user-content-import-declaration), [constant-declaration](#user-content-constant-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_;
diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt
index 6de3dfcb43..d62c2900fd 100644
--- a/grammar/abnf-grammar.txt
+++ b/grammar/abnf-grammar.txt
@@ -938,7 +938,7 @@ function-input = [ %s"const" ] identifier ":" type
; A circuit member variable declaration consists of an identifier and a type.
; A circuit member function declaration consists of a function declaration.
-member-variable-declaration = identifier ":" type ( "," / ";" )
+member-variable-declaration = *(identifier ":" type ( "," / ";" )) identifier ":" type ( [ "," ] / ";" )
member-function-declaration = function-declaration
diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs
index 58fc165b26..586d94a6bb 100644
--- a/parser/src/parser/file.rs
+++ b/parser/src/parser/file.rs
@@ -282,12 +282,24 @@ impl ParserContext {
///
pub fn parse_circuit_declaration(&mut self) -> SyntaxResult> {
let mut members = Vec::new();
+ let peeked = &self.peek()?.token;
+ let mut last_variable = peeked == &Token::Function || peeked == &Token::At;
while self.eat(Token::RightCurly).is_none() {
- let peeked = &self.peek()?.token;
-
- if !(peeked == &Token::Function || peeked == &Token::At) {
- let variable = self.parse_member_variable_declaration()?;
+ if !last_variable {
+ let (variable, last) = self.parse_member_variable_declaration()?;
members.push(variable);
+
+ if !last {
+ self.expect_oneof(&[Token::Comma, Token::Semicolon])?;
+ } else {
+ last_variable = last;
+ let peeked = &self.peek()?.token;
+ if peeked == &Token::Semicolon {
+ self.expect(Token::Semicolon)?;
+ } else {
+ self.eat(Token::Comma);
+ }
+ }
} else {
let function = self.parse_member_function_declaration()?;
members.push(function);
@@ -301,14 +313,19 @@ impl ParserContext {
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable
/// or circuit member function.
///
- pub fn parse_member_variable_declaration(&mut self) -> SyntaxResult {
+ pub fn parse_member_variable_declaration(&mut self) -> SyntaxResult<(CircuitMember, bool)> {
let name = self.expect_ident()?;
self.expect(Token::Colon)?;
let type_ = self.parse_type()?.0;
- self.expect_oneof(&[Token::Comma, Token::Semicolon])?;
+ let peeked = &self.peek()?;
+ let peeked_token = &peeked.token;
- Ok(CircuitMember::CircuitVariable(name, type_))
+ if peeked_token == &Token::Function || peeked_token == &Token::At || peeked_token == &Token::RightCurly {
+ return Ok((CircuitMember::CircuitVariable(name, type_), true));
+ }
+
+ Ok((CircuitMember::CircuitVariable(name, type_), false))
}
///
@@ -324,13 +341,7 @@ impl ParserContext {
} else {
Err(SyntaxError::unexpected(
peeked_token,
- &[
- Token::Import,
- Token::Circuit,
- Token::Function,
- Token::Ident("test".into()),
- Token::At,
- ],
+ &[Token::Function, Token::At],
&peeked.span,
))
}