Merge pull request #896 from Zokrates/fix-multi-assignee-parsing
Fix multi assignee parsing
This commit is contained in:
commit
e4ef841ec7
6 changed files with 118 additions and 100 deletions
1
changelogs/unreleased/896-schaeff
Normal file
1
changelogs/unreleased/896-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Fix parsing of the left hand side of definitions
|
11
zokrates_cli/examples/assign_to_element.zok
Normal file
11
zokrates_cli/examples/assign_to_element.zok
Normal file
|
@ -0,0 +1,11 @@
|
|||
def foo() -> u32:
|
||||
return 0
|
||||
|
||||
def bar() -> (u32, u32):
|
||||
return 0, 0
|
||||
|
||||
|
||||
def main(u32[1] a, u32 b):
|
||||
a[0] = foo()
|
||||
a[0], b = bar()
|
||||
return
|
|
@ -0,0 +1,3 @@
|
|||
def main():
|
||||
field[2] a[2] = [1, 2] // only variables can be declared in such a statement, declaring `a[2]` is invalid
|
||||
return
|
|
@ -239,54 +239,73 @@ fn statements_from_definition(definition: pest::DefinitionStatement) -> Vec<absy
|
|||
|
||||
let e: absy::ExpressionNode = absy::ExpressionNode::from(definition.expression);
|
||||
|
||||
let s = match e.value {
|
||||
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
|
||||
vec![absy::AssigneeNode::from(a.a.clone())],
|
||||
e,
|
||||
),
|
||||
_ => absy::Statement::Definition(absy::AssigneeNode::from(a.a.clone()), e),
|
||||
};
|
||||
|
||||
match a.ty {
|
||||
Some(ty) => {
|
||||
assert_eq!(a.a.accesses.len(), 0);
|
||||
|
||||
match a {
|
||||
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
|
||||
let declaration = absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
a.a.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(ty),
|
||||
i.identifier.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(i.ty),
|
||||
)
|
||||
.span(a.a.id.span.clone()),
|
||||
.span(i.identifier.span.clone()),
|
||||
)
|
||||
.span(definition.span.clone());
|
||||
|
||||
let s = match e.value {
|
||||
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
|
||||
vec![absy::AssigneeNode::from(i.identifier.clone())],
|
||||
e,
|
||||
),
|
||||
_ => absy::Statement::Definition(
|
||||
absy::AssigneeNode::from(i.identifier.clone()),
|
||||
e,
|
||||
),
|
||||
};
|
||||
|
||||
vec![declaration, s.span(definition.span)]
|
||||
}
|
||||
None => {
|
||||
// Assignment
|
||||
pest::TypedIdentifierOrAssignee::Assignee(a) => {
|
||||
let s = match e.value {
|
||||
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
|
||||
vec![absy::AssigneeNode::from(a)],
|
||||
e,
|
||||
),
|
||||
_ => absy::Statement::Definition(absy::AssigneeNode::from(a), e),
|
||||
};
|
||||
|
||||
vec![s.span(definition.span)]
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Multidefinition
|
||||
let declarations = lhs.clone().into_iter().filter(|i| i.ty.is_some()).map(|a| {
|
||||
let ty = a.ty;
|
||||
let a = a.a;
|
||||
let declarations = lhs.clone().into_iter().filter_map(|i| match i {
|
||||
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
|
||||
let ty = i.ty;
|
||||
let id = i.identifier;
|
||||
|
||||
assert_eq!(a.accesses.len(), 0);
|
||||
absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
a.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(ty.unwrap()),
|
||||
Some(
|
||||
absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(ty),
|
||||
)
|
||||
.span(id.span),
|
||||
)
|
||||
.span(i.span),
|
||||
)
|
||||
.span(a.id.span),
|
||||
)
|
||||
.span(a.span)
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let lhs = lhs
|
||||
.into_iter()
|
||||
.map(|i| absy::Assignee::Identifier(i.a.id.span.as_str()).span(i.a.id.span))
|
||||
.map(|i| match i {
|
||||
pest::TypedIdentifierOrAssignee::TypedIdentifier(i) => {
|
||||
absy::Assignee::Identifier(i.identifier.span.as_str())
|
||||
.span(i.identifier.span)
|
||||
}
|
||||
pest::TypedIdentifierOrAssignee::Assignee(a) => absy::AssigneeNode::from(a),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let multi_def = absy::Statement::MultipleDefinition(
|
||||
|
@ -1096,18 +1115,14 @@ mod tests {
|
|||
// A `Definition` is generated and no `Declaration`s
|
||||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
lhs: vec![pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
}],
|
||||
})],
|
||||
expression: pest::Expression::Literal(pest::LiteralExpression::DecimalLiteral(
|
||||
pest::DecimalLiteralExpression {
|
||||
value: pest::DecimalNumber {
|
||||
|
@ -1134,18 +1149,14 @@ mod tests {
|
|||
// A MultiDef is generated
|
||||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
lhs: vec![pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
}],
|
||||
})],
|
||||
expression: pest::Expression::Postfix(pest::PostfixExpression {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("foo"),
|
||||
|
@ -1180,32 +1191,24 @@ mod tests {
|
|||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![
|
||||
pest::OptionallyTypedAssignee {
|
||||
ty: Some(pest::Type::Basic(pest::BasicType::Field(pest::FieldType {
|
||||
pest::TypedIdentifierOrAssignee::TypedIdentifier(pest::TypedIdentifier {
|
||||
ty: pest::Type::Basic(pest::BasicType::Field(pest::FieldType {
|
||||
span: span.clone(),
|
||||
}))),
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
})),
|
||||
identifier: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
span: span.clone(),
|
||||
},
|
||||
pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
}),
|
||||
pest::TypedIdentifierOrAssignee::Assignee(pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
},
|
||||
}),
|
||||
],
|
||||
expression: pest::Expression::Postfix(pest::PostfixExpression {
|
||||
id: pest::IdentifierExpression {
|
||||
|
|
|
@ -54,11 +54,11 @@ statement = { (return_statement // does not require subsequent newline
|
|||
|
||||
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
||||
return_statement = { "return" ~ expression_list}
|
||||
definition_statement = { optionally_typed_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||
definition_statement = { typed_identifier_or_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||
expression_statement = {"assert" ~ "(" ~ expression ~ ")"}
|
||||
|
||||
optionally_typed_assignee_list = _{ optionally_typed_assignee ~ ("," ~ optionally_typed_assignee)* }
|
||||
optionally_typed_assignee = { (ty ~ assignee) | (assignee) } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
|
||||
typed_identifier_or_assignee_list = _{ typed_identifier_or_assignee ~ ("," ~ typed_identifier_or_assignee)* }
|
||||
typed_identifier_or_assignee = { typed_identifier | assignee } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
|
||||
|
||||
// Expressions
|
||||
expression_list = _{(expression ~ ("," ~ expression)*)?}
|
||||
|
@ -103,6 +103,7 @@ array_initializer_expression = { "[" ~ expression ~ ";" ~ expression ~ "]" }
|
|||
|
||||
// End Expressions
|
||||
|
||||
typed_identifier = { ty ~ identifier }
|
||||
assignee = { identifier ~ assignee_access* }
|
||||
assignee_access = { array_access | member_access }
|
||||
identifier = @{ ((!keyword ~ ASCII_ALPHA) | (keyword ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
|
|
|
@ -14,11 +14,11 @@ pub use ast::{
|
|||
DecimalSuffix, DefinitionStatement, ExplicitGenerics, Expression, FieldType, File,
|
||||
FromExpression, FunctionDefinition, HexLiteralExpression, HexNumberExpression,
|
||||
IdentifierExpression, ImportDirective, ImportSource, ImportSymbol, InlineArrayExpression,
|
||||
InlineStructExpression, InlineStructMember, IterationStatement, LiteralExpression,
|
||||
OptionallyTypedAssignee, Parameter, PostfixExpression, Range, RangeOrExpression,
|
||||
ReturnStatement, Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField,
|
||||
SymbolDeclaration, TernaryExpression, ToExpression, Type, UnaryExpression, UnaryOperator,
|
||||
Underscore, Visibility,
|
||||
InlineStructExpression, InlineStructMember, IterationStatement, LiteralExpression, Parameter,
|
||||
PostfixExpression, Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression,
|
||||
Statement, StructDefinition, StructField, SymbolDeclaration, TernaryExpression, ToExpression,
|
||||
Type, TypedIdentifier, TypedIdentifierOrAssignee, UnaryExpression, UnaryOperator, Underscore,
|
||||
Visibility,
|
||||
};
|
||||
|
||||
mod ast {
|
||||
|
@ -349,7 +349,7 @@ mod ast {
|
|||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::definition_statement))]
|
||||
pub struct DefinitionStatement<'ast> {
|
||||
pub lhs: Vec<OptionallyTypedAssignee<'ast>>,
|
||||
pub lhs: Vec<TypedIdentifierOrAssignee<'ast>>,
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -635,10 +635,17 @@ mod ast {
|
|||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::optionally_typed_assignee))]
|
||||
pub struct OptionallyTypedAssignee<'ast> {
|
||||
pub ty: Option<Type<'ast>>,
|
||||
pub a: Assignee<'ast>,
|
||||
#[pest_ast(rule(Rule::typed_identifier_or_assignee))]
|
||||
pub enum TypedIdentifierOrAssignee<'ast> {
|
||||
Assignee(Assignee<'ast>),
|
||||
TypedIdentifier(TypedIdentifier<'ast>),
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::typed_identifier))]
|
||||
pub struct TypedIdentifier<'ast> {
|
||||
pub ty: Type<'ast>,
|
||||
pub identifier: IdentifierExpression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
@ -1330,32 +1337,24 @@ mod tests {
|
|||
}))],
|
||||
statements: vec![Statement::Definition(DefinitionStatement {
|
||||
lhs: vec![
|
||||
OptionallyTypedAssignee {
|
||||
ty: Some(Type::Basic(BasicType::Field(FieldType {
|
||||
TypedIdentifierOrAssignee::TypedIdentifier(TypedIdentifier {
|
||||
ty: Type::Basic(BasicType::Field(FieldType {
|
||||
span: Span::new(&source, 23, 28).unwrap()
|
||||
}))),
|
||||
a: Assignee {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: Span::new(&source, 29, 30).unwrap(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: Span::new(&source, 29, 30).unwrap()
|
||||
})),
|
||||
identifier: IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: Span::new(&source, 29, 30).unwrap(),
|
||||
},
|
||||
span: Span::new(&source, 23, 30).unwrap()
|
||||
},
|
||||
OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: Assignee {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: Span::new(&source, 32, 33).unwrap(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: Span::new(&source, 32, 34).unwrap()
|
||||
}),
|
||||
TypedIdentifierOrAssignee::Assignee(Assignee {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: Span::new(&source, 32, 33).unwrap(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: Span::new(&source, 32, 34).unwrap()
|
||||
},
|
||||
}),
|
||||
],
|
||||
expression: Expression::Postfix(PostfixExpression {
|
||||
id: IdentifierExpression {
|
||||
|
|
Loading…
Reference in a new issue