1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Merge pull request #896 from Zokrates/fix-multi-assignee-parsing

Fix multi assignee parsing
This commit is contained in:
Thibaut Schaeffer 2021-06-01 09:48:18 +02:00 committed by GitHub
commit e4ef841ec7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 100 deletions

View file

@ -0,0 +1 @@
Fix parsing of the left hand side of definitions

View 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

View file

@ -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

View file

@ -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 {

View file

@ -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 | "_")* }

View file

@ -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 {