From a32418133c393a087d9889960618213cf777ff10 Mon Sep 17 00:00:00 2001 From: collin <16715212+collinc97@users.noreply.github.com> Date: Thu, 9 Jun 2022 13:01:59 -0700 Subject: [PATCH] parse method calls directly --- compiler/ast/src/expression/binary.rs | 55 ++++++------------ compiler/parser/src/parser/expression.rs | 58 ++++++++++++++----- .../src/type_checker/check_expressions.rs | 7 +++ compiler/passes/src/type_checker/checker.rs | 5 ++ leo/span/src/symbol.rs | 55 +++++++++++------- 5 files changed, 107 insertions(+), 73 deletions(-) diff --git a/compiler/ast/src/expression/binary.rs b/compiler/ast/src/expression/binary.rs index 52ac5b40ec..7c75f97433 100644 --- a/compiler/ast/src/expression/binary.rs +++ b/compiler/ast/src/expression/binary.rs @@ -21,8 +21,10 @@ use super::*; /// Precedence is defined in the parser. #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BinaryOperation { - /// Addition, i.e. `+`. + /// Addition, i.e. `+`, `.add()`. Add, + /// Wrapped addition, i.e. `.add_wrapped()`. + AddWrapped, /// Subtraction, i.e. `-`. Sub, /// Multiplication, i.e. `*`. @@ -61,41 +63,20 @@ pub enum BinaryOperationClass { impl AsRef for BinaryOperation { fn as_ref(&self) -> &'static str { match self { - BinaryOperation::Add => "+", - BinaryOperation::Sub => "-", - BinaryOperation::Mul => "*", - BinaryOperation::Div => "/", - BinaryOperation::Pow => "**", - BinaryOperation::Or => "||", - BinaryOperation::And => "&&", - BinaryOperation::Eq => "==", - BinaryOperation::Ne => "!=", - BinaryOperation::Ge => ">=", - BinaryOperation::Gt => ">", - BinaryOperation::Le => "<=", - BinaryOperation::Lt => "<", - } - } -} - -impl BinaryOperation { - /// The class ("category") that the binary operation belongs to. - /// For example, the `+` operator is numeric and `==` results in a boolean value. - pub fn class(&self) -> BinaryOperationClass { - match self { - BinaryOperation::Add - | BinaryOperation::Sub - | BinaryOperation::Mul - | BinaryOperation::Div - | BinaryOperation::Pow => BinaryOperationClass::Numeric, - BinaryOperation::Or - | BinaryOperation::And - | BinaryOperation::Eq - | BinaryOperation::Ne - | BinaryOperation::Ge - | BinaryOperation::Gt - | BinaryOperation::Le - | BinaryOperation::Lt => BinaryOperationClass::Boolean, + BinaryOperation::Add => "add", + BinaryOperation::AddWrapped => "add_wrapped", + BinaryOperation::Sub => "sub", + BinaryOperation::Mul => "mul", + BinaryOperation::Div => "div", + BinaryOperation::Pow => "pow", + BinaryOperation::Or => "or", + BinaryOperation::And => "and", + BinaryOperation::Eq => "eq", + BinaryOperation::Ne => "ne", + BinaryOperation::Ge => "ge", + BinaryOperation::Gt => "gt", + BinaryOperation::Le => "le", + BinaryOperation::Lt => "lt", } } } @@ -116,7 +97,7 @@ pub struct BinaryExpression { impl fmt::Display for BinaryExpression { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {} {}", self.left, self.op.as_ref(), self.right) + write!(f, "{}.{}({})", self.left, self.op.as_ref(), self.right) } } diff --git a/compiler/parser/src/parser/expression.rs b/compiler/parser/src/parser/expression.rs index cbb7a8e7ed..57bd57e4c8 100644 --- a/compiler/parser/src/parser/expression.rs +++ b/compiler/parser/src/parser/expression.rs @@ -218,6 +218,48 @@ impl ParserContext<'_> { Ok(inner) } + fn parse_method_call_expression(&mut self, receiver: Expression) -> Result { + // Get the name of the method. + if let Token::Ident(method) = self.token.token { + self.bump(); + + // Check if the method exists. + let index = method.as_u32(); + + if index <= 2 { + // Binary operators. + let operator = match index { + 1 => BinaryOperation::Add, + 2 => BinaryOperation::AddWrapped, + _ => unimplemented!("throw error for invalid method call") + }; + + // Parse left parenthesis `(`. + self.expect(&Token::LeftParen)?; + + // Parse operand. + let operand = self.parse_expression()?; + + // Parse close parenthesis `)`. + let right_span = self.expect(&Token::RightParen)?; + + return Ok(Expression::Binary(BinaryExpression { + span: receiver.span() + right_span, + op: operator, + left: Box::new(receiver), + right: Box::new(operand), + })) + + } else { + // handle core module operators `commit`, `hash` etc. + unimplemented!("throw error for invalid method call") + } + } else { + let curr = &self.token; + Err(ParserError::unexpected_str(&curr.token, "int or ident", curr.span).into()) + } + } + /// Returns an [`Expression`] AST node if the next tokens represent an /// array access, circuit member access, function call, or static function call expression. /// @@ -229,21 +271,7 @@ impl ParserContext<'_> { let mut expr = self.parse_primary_expression()?; loop { if self.eat(&Token::Dot) { - // Handle method call expression. - if let Some(method) = self.eat_identifier() { - if self.check(&Token::LeftParen) { - let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?; - expr = Expression::Method(MethodCallExpression { - span: expr.span() + span, - receiver: Box::new(expr), - method, - arguments, - }); - continue; - } - } - let curr = &self.token; - return Err(ParserError::unexpected_str(&curr.token, "int or ident", curr.span).into()); + expr = self.parse_method_call_expression(expr)? } if !self.check(&Token::LeftParen) { break; diff --git a/compiler/passes/src/type_checker/check_expressions.rs b/compiler/passes/src/type_checker/check_expressions.rs index 34b06ce30d..ec00cb2529 100644 --- a/compiler/passes/src/type_checker/check_expressions.rs +++ b/compiler/passes/src/type_checker/check_expressions.rs @@ -311,6 +311,13 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> { Some(Type::Boolean) } + BinaryOperation::AddWrapped => { + self.visitor.assert_int_type(expected, input.span); + let t1 = self.visit_expression(&input.left, expected); + let t2 = self.visit_expression(&input.right, expected); + + return_incorrect_type(t1, t2, expected) + } }; } diff --git a/compiler/passes/src/type_checker/checker.rs b/compiler/passes/src/type_checker/checker.rs index 0c4a166601..29d5ffff51 100644 --- a/compiler/passes/src/type_checker/checker.rs +++ b/compiler/passes/src/type_checker/checker.rs @@ -138,6 +138,11 @@ impl<'a> TypeChecker<'a> { } } + /// Emits an error to the handler if the given type is not an integer. + pub(crate) fn assert_int_type(&self, type_: &Option, span: Span) { + self.assert_one_of_types(type_, &INT_TYPES, span) + } + /// Emits an error to the handler if the given type is not a field or integer. pub(crate) fn assert_field_int_type(&self, type_: &Option, span: Span) { self.assert_one_of_types(type_, &FIELD_INT_TYPES, span) diff --git a/leo/span/src/symbol.rs b/leo/span/src/symbol.rs index ef147e3322..37f26b96ac 100644 --- a/leo/span/src/symbol.rs +++ b/leo/span/src/symbol.rs @@ -100,30 +100,51 @@ macro_rules! symbols { } symbols! { + // unary operators + + // binary operators + add, + add_w, + + // arity three operators + + // types address, - AlwaysConst, array, - assert, bool, - Class: "class", - context, - constants, - CoreFunction, - console, Const: "const", Constant, - Else: "else", - error, - False: "false", + constants, field, - For: "for", - function, group, i8, i16, i32, i64, i128, + scalar, + string, + u8, + u16, + u32, + u64, + u128, + + // values + False: "false", + True: "true", + + // general keywords + AlwaysConst, + assert, + Class: "class", + context, + CoreFunction, + console, + Else: "else", + error, + For: "for", + function, If: "if", In: "in", input, @@ -134,19 +155,11 @@ symbols! { prelude, Public, Return: "return", - scalar, Star: "*", std, - string, Struct: "struct", test, - True: "true", Type: "type", - u8, - u16, - u32, - u64, - u128, CONTAINER_PSEUDO_CIRCUIT: "$InputContainer", REGISTERS_PSEUDO_CIRCUIT: "$InputRegister", @@ -154,11 +167,11 @@ symbols! { STATE_PSEUDO_CIRCUIT: "$InputState", STATE_LEAF_PSEUDO_CIRCUIT: "$InputStateLeaf", + // input file registers, record, state, state_leaf, - public, private, }