From 6f4501ba8ab838de3c1806a034b89171e47abcb4 Mon Sep 17 00:00:00 2001 From: schaeff Date: Tue, 23 Mar 2021 12:24:35 +0100 Subject: [PATCH] implement python precedence in the parser, use derives in ast generation --- zokrates_core/src/absy/from_ast.rs | 20 +- zokrates_core/src/compile.rs | 2 + zokrates_core_test/tests/tests/precedence.zok | 2 + zokrates_parser/src/zokrates.pest | 14 +- zokrates_pest_ast/src/lib.rs | 234 +++++++++++------- 5 files changed, 166 insertions(+), 106 deletions(-) diff --git a/zokrates_core/src/absy/from_ast.rs b/zokrates_core/src/absy/from_ast.rs index be2cec1b..1455f362 100644 --- a/zokrates_core/src/absy/from_ast.rs +++ b/zokrates_core/src/absy/from_ast.rs @@ -500,21 +500,17 @@ impl<'ast> From> for absy::ExpressionNode } impl<'ast> From> for absy::ExpressionNode<'ast> { - fn from(unary: pest::UnaryExpression<'ast>) -> absy::ExpressionNode<'ast> { + fn from(e: pest::UnaryExpression<'ast>) -> absy::ExpressionNode<'ast> { use crate::absy::NodeValue; - match unary.op { - pest::UnaryOperator::Not(_) => { - absy::Expression::Not(Box::new(absy::ExpressionNode::from(*unary.expression))) - } - pest::UnaryOperator::Neg(_) => { - absy::Expression::Neg(Box::new(absy::ExpressionNode::from(*unary.expression))) - } - pest::UnaryOperator::Pos(_) => { - absy::Expression::Pos(Box::new(absy::ExpressionNode::from(*unary.expression))) - } + let expression = Box::new(absy::ExpressionNode::from(*e.expression)); + + match e.op { + pest::UnaryOperator::Not(..) => absy::Expression::Not(expression), + pest::UnaryOperator::Neg(..) => absy::Expression::Neg(expression), + pest::UnaryOperator::Pos(..) => absy::Expression::Pos(expression), } - .span(unary.span) + .span(e.span) } } diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index 7711a52a..9b5b48ed 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -203,6 +203,8 @@ fn check_with_arena<'ast, T: Field, E: Into>( CompileErrors(errors.into_iter().map(|e| CompileError::from(e)).collect()) })?; + println!("{}", typed_ast); + let abi = typed_ast.abi(); // analyse (unroll and constant propagation) diff --git a/zokrates_core_test/tests/tests/precedence.zok b/zokrates_core_test/tests/tests/precedence.zok index 0d699a9a..e3ed0cfa 100644 --- a/zokrates_core_test/tests/tests/precedence.zok +++ b/zokrates_core_test/tests/tests/precedence.zok @@ -13,6 +13,8 @@ def main(): assert(0x00 ^ 0x00 == 0x00) + assert(0 - 2 ** 2 == -4) + //check if all statements have evalutated to true assert(a * b * c * d * e * f == 1) return diff --git a/zokrates_parser/src/zokrates.pest b/zokrates_parser/src/zokrates.pest index 612ce20d..f4a33f51 100644 --- a/zokrates_parser/src/zokrates.pest +++ b/zokrates_parser/src/zokrates.pest @@ -55,8 +55,10 @@ optionally_typed_assignee = { (ty ~ assignee) | (assignee) } // we don't use { t // Expressions expression_list = _{(expression ~ ("," ~ expression)*)?} -expression = { term ~ (op_binary ~ term)* } -term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression | unary_expression } +expression = { unaried_term ~ (op_binary ~ unaried_term)* } +unaried_term = { op_unary? ~ powered_term } +powered_term = { term ~ (op_pow ~ exponent_expression)? } +term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression } spread = { "..." ~ expression } range = { from_expression? ~ ".." ~ to_expression? } from_expression = { expression } @@ -84,7 +86,8 @@ spread_or_expression = { spread | expression } range_or_expression = { range | expression } array_initializer_expression = { "[" ~ expression ~ ";" ~ constant ~ "]" } -unary_expression = { op_unary ~ term } +signeable_expression = { "(" ~ expression ~ ")" | primary_expression } +exponent_expression = { "(" ~ expression ~ ")" | primary_expression } // End Expressions @@ -121,9 +124,8 @@ op_neg = {"-"} op_pos = {"+"} op_left_shift = @{"<<"} op_right_shift = @{">>"} -op_binary = _ { op_pow | op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem } -op_unary = { op_not | op_neg | op_pos } - +op_binary = _ { op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem } +op_unary = { op_pos | op_neg | op_not } WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE} COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) } diff --git a/zokrates_pest_ast/src/lib.rs b/zokrates_pest_ast/src/lib.rs index bbff5489..a81dd0d4 100644 --- a/zokrates_pest_ast/src/lib.rs +++ b/zokrates_pest_ast/src/lib.rs @@ -12,7 +12,7 @@ pub use ast::{ AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator, CallAccess, ConstantExpression, DecimalNumberExpression, DefinitionStatement, Expression, FieldType, File, FromExpression, Function, IdentifierExpression, ImportDirective, ImportSource, - InlineArrayExpression, InlineStructExpression, InlineStructMember, IterationStatement, + InlineArrayExpression, InlineStructExpression, InlineStructMember, IterationStatement, Not, OptionallyTypedAssignee, Parameter, PostfixExpression, Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField, TernaryExpression, ToExpression, Type, UnaryExpression, UnaryOperator, Visibility, @@ -52,7 +52,6 @@ mod ast { Operator::new(Rule::op_mul, Assoc::Left) | Operator::new(Rule::op_div, Assoc::Left) | Operator::new(Rule::op_rem, Assoc::Left), - Operator::new(Rule::op_pow, Assoc::Left), ]) } @@ -74,7 +73,6 @@ mod ast { Rule::op_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span), Rule::op_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span), Rule::op_rem => Expression::binary(BinaryOperator::Rem, lhs, rhs, span), - Rule::op_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span), Rule::op_equal => Expression::binary(BinaryOperator::Eq, lhs, rhs, span), Rule::op_not_equal => Expression::binary(BinaryOperator::NotEq, lhs, rhs, span), Rule::op_lte => Expression::binary(BinaryOperator::Lte, lhs, rhs, span), @@ -97,74 +95,12 @@ mod ast { PREC_CLIMBER.climb(pair.into_inner(), build_factor, infix_rule) } - // Create an Expression from a `term`. - // Precondition: `pair` MUST be a term + // Create an Expression from a `signed_term`. + // Precondition: `pair` MUST be a signed_term fn build_factor(pair: Pair) -> Box { - Box::new(match pair.as_rule() { - Rule::term => { - // clone the pair to peek into what we should create - let clone = pair.clone(); - // define the child pair - let next = clone.into_inner().next().unwrap(); - match next.as_rule() { - // this happens when we have an expression in parentheses: it needs to be processed as another sequence of terms and operators - Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), - Rule::conditional_expression => Expression::Ternary( - TernaryExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::primary_expression => { - // maybe this could be simplified - let next = next.into_inner().next().unwrap(); - match next.as_rule() { - Rule::constant => Expression::Constant( - ConstantExpression::from_pest( - &mut pair.into_inner().next().unwrap().into_inner(), - ) - .unwrap(), - ), - Rule::identifier => Expression::Identifier( - IdentifierExpression::from_pest( - &mut pair.into_inner().next().unwrap().into_inner(), - ) - .unwrap(), - ), - r => unreachable!("`primary_expression` should contain one of [`constant`, `identifier`], found {:#?}", r), - } - } - Rule::postfix_expression => Expression::Postfix( - PostfixExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::inline_struct_expression => Expression::InlineStruct( - InlineStructExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::inline_array_expression => Expression::InlineArray( - InlineArrayExpression::from_pest(&mut pair.into_inner()).unwrap(), - ), - Rule::array_initializer_expression => Expression::ArrayInitializer( - ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap() - ), - Rule::unary_expression => { - let span = next.as_span(); - let mut inner = next.into_inner(); - let op = match inner.next().unwrap().as_rule() { - Rule::op_unary => UnaryOperator::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(), - r => unreachable!("`unary_expression` should yield `op_unary`, found {:#?}", r) - }; - let expression = build_factor(inner.next().unwrap()); - Expression::Unary(UnaryExpression { - op, - expression, - span - }) - }, - r => unreachable!("`term` should contain one of [`expression`, `conditional_expression`, `primary_expression`, `postfix_expression`, `inline_array_expression`, `unary_expression`, `array_initializer_expression`], found {:#?}", r) - } - } - r => unreachable!( - "`build_factor` can only be called on `term`, found {:#?}", - r - ), - }) + Box::new(Expression::from( + UnariedTerm::from_pest(&mut Pairs::single(pair)).unwrap(), + )) } #[derive(Debug, FromPest, PartialEq, Clone)] @@ -431,14 +367,6 @@ mod ast { Pow, } - #[derive(Debug, PartialEq, FromPest, Clone)] - #[pest_ast(rule(Rule::op_unary))] - pub enum UnaryOperator<'ast> { - Not(Not<'ast>), - Neg(Neg<'ast>), - Pos(Pos<'ast>), - } - #[derive(Debug, PartialEq, FromPest, Clone)] #[pest_ast(rule(Rule::op_not))] pub struct Not<'ast> { @@ -464,13 +392,145 @@ mod ast { pub enum Expression<'ast> { Ternary(TernaryExpression<'ast>), Binary(BinaryExpression<'ast>), + Unary(UnaryExpression<'ast>), Postfix(PostfixExpression<'ast>), Identifier(IdentifierExpression<'ast>), Constant(ConstantExpression<'ast>), InlineArray(InlineArrayExpression<'ast>), InlineStruct(InlineStructExpression<'ast>), ArrayInitializer(ArrayInitializerExpression<'ast>), - Unary(UnaryExpression<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::term))] + pub enum Term<'ast> { + Expression(Expression<'ast>), + InlineStruct(InlineStructExpression<'ast>), + Ternary(TernaryExpression<'ast>), + Postfix(PostfixExpression<'ast>), + Primary(PrimaryExpression<'ast>), + InlineArray(InlineArrayExpression<'ast>), + ArrayInitializer(ArrayInitializerExpression<'ast>), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::powered_term))] + struct PoweredTerm<'ast> { + base: Term<'ast>, + op: Option, + exponent: Option>, + #[pest_ast(outer())] + span: Span<'ast>, + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_pow))] + struct PowOp; + + impl<'ast> From> for Expression<'ast> { + fn from(t: PoweredTerm<'ast>) -> Self { + let base = Expression::from(t.base); + + match t.exponent { + Some(exponent) => Expression::Binary(BinaryExpression { + op: BinaryOperator::Pow, + left: Box::new(base), + right: Box::new(exponent.into()), + span: t.span, + }), + None => base, + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::unaried_term))] + struct UnariedTerm<'ast> { + op: Option, + expression: PoweredTerm<'ast>, + #[pest_ast(outer())] + span: Span<'ast>, + } + + impl<'ast> From> for Expression<'ast> { + fn from(t: UnariedTerm<'ast>) -> Self { + let expression = Expression::from(t.expression); + + match t.op { + Some(sign) => Expression::Unary(UnaryExpression { + op: sign.into(), + expression: Box::new(expression), + span: t.span, + }), + None => expression, + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_unary))] + pub enum UnaryOperator { + Pos(PosOperator), + Neg(NegOperator), + Not(NotOperator), + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_pos))] + pub struct PosOperator; + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_neg))] + pub struct NegOperator; + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::op_not))] + pub struct NotOperator; + + impl<'ast> From> for Expression<'ast> { + fn from(t: Term<'ast>) -> Self { + match t { + Term::Expression(e) => e, + Term::Ternary(e) => Expression::Ternary(e), + Term::Postfix(e) => Expression::Postfix(e), + Term::Primary(e) => e.into(), + Term::InlineArray(e) => Expression::InlineArray(e), + Term::InlineStruct(e) => Expression::InlineStruct(e), + Term::ArrayInitializer(e) => Expression::ArrayInitializer(e), + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::primary_expression))] + pub enum PrimaryExpression<'ast> { + Identifier(IdentifierExpression<'ast>), + Constant(ConstantExpression<'ast>), + } + + impl<'ast> From> for Expression<'ast> { + fn from(e: PrimaryExpression<'ast>) -> Self { + match e { + PrimaryExpression::Constant(c) => Expression::Constant(c), + PrimaryExpression::Identifier(i) => Expression::Identifier(i), + } + } + } + + #[derive(Debug, FromPest, PartialEq, Clone)] + #[pest_ast(rule(Rule::exponent_expression))] + pub enum ExponentExpression<'ast> { + Expression(Expression<'ast>), + Primary(PrimaryExpression<'ast>), + } + + impl<'ast> From> for Expression<'ast> { + fn from(e: ExponentExpression<'ast>) -> Self { + match e { + ExponentExpression::Expression(e) => e, + ExponentExpression::Primary(e) => e.into(), + } + } } #[derive(Debug, FromPest, PartialEq, Clone)] @@ -521,15 +581,6 @@ mod ast { pub span: Span<'ast>, } - #[derive(Debug, FromPest, PartialEq, Clone)] - #[pest_ast(rule(Rule::unary_expression))] - pub struct UnaryExpression<'ast> { - pub op: UnaryOperator<'ast>, - pub expression: Box>, - #[pest_ast(outer())] - pub span: Span<'ast>, - } - #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::inline_array_expression))] pub struct InlineArrayExpression<'ast> { @@ -621,6 +672,13 @@ mod ast { pub span: Span<'ast>, } + #[derive(Debug, PartialEq, Clone)] + pub struct UnaryExpression<'ast> { + pub op: UnaryOperator, + pub expression: Box>, + pub span: Span<'ast>, + } + #[derive(Debug, FromPest, PartialEq, Clone)] #[pest_ast(rule(Rule::conditional_expression))] pub struct TernaryExpression<'ast> {