From f0a1573058e9977a540918011599df0faea8cfd8 Mon Sep 17 00:00:00 2001
From: collin <16715212+collinc97@users.noreply.github.com>
Date: Fri, 3 Jun 2022 13:27:23 -0400
Subject: [PATCH] impl method call expression parsing
---
compiler/ast/src/expression/method.rs | 46 +++++++++++++++++++
compiler/ast/src/expression/mod.rs | 9 +++-
.../ast/src/passes/reconstructing_director.rs | 13 ++++++
.../ast/src/passes/reconstructing_reducer.rs | 15 ++++++
compiler/ast/src/passes/visitor.rs | 4 ++
compiler/ast/src/passes/visitor_director.rs | 11 +++++
compiler/parser/src/parser/expression.rs | 16 ++++++-
.../src/type_checker/check_expressions.rs | 35 ++++++++++++++
examples/hello-world/src/main.leo | 5 +-
9 files changed, 149 insertions(+), 5 deletions(-)
create mode 100644 compiler/ast/src/expression/method.rs
diff --git a/compiler/ast/src/expression/method.rs b/compiler/ast/src/expression/method.rs
new file mode 100644
index 0000000000..6af3cbc79e
--- /dev/null
+++ b/compiler/ast/src/expression/method.rs
@@ -0,0 +1,46 @@
+// Copyright (C) 2019-2022 Aleo Systems Inc.
+// This file is part of the Leo library.
+
+// The Leo library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// The Leo library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with the Leo library. If not, see .
+
+use super::*;
+
+/// A method call expression, e.g., `1u8.add(2u8)`.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct MethodCallExpression {
+ /// The receiver of a method call, e.g. `1u8` in `1u8.add(2u8)`.
+ pub receiver: Box,
+ /// The identifier of the called method.
+ pub method: Identifier,
+ /// Expressions for the arguments passed to the methods parameters.
+ pub arguments: Vec,
+ /// Span of the entire call `receiver.method(arguments)`.
+ pub span: Span,
+}
+
+impl fmt::Display for MethodCallExpression {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}.", self.receiver)?;
+ write!(f, "{}(", self.method)?;
+ for (i, param) in self.arguments.iter().enumerate() {
+ write!(f, "{}", param)?;
+ if i < self.arguments.len() - 1 {
+ write!(f, ", ")?;
+ }
+ }
+ write!(f, ")")
+ }
+}
+
+crate::simple_node_impl!(MethodCallExpression);
diff --git a/compiler/ast/src/expression/mod.rs b/compiler/ast/src/expression/mod.rs
index 4b6ee17b44..3f2ece2cf7 100644
--- a/compiler/ast/src/expression/mod.rs
+++ b/compiler/ast/src/expression/mod.rs
@@ -24,6 +24,8 @@ mod binary;
pub use binary::*;
mod unary;
pub use unary::*;
+mod method;
+pub use method::*;
mod ternary;
pub use ternary::*;
mod value;
@@ -46,8 +48,10 @@ pub enum Expression {
Unary(UnaryExpression),
/// A ternary conditional expression `cond ? if_expr : else_expr`.
Ternary(TernaryExpression),
- /// A call expression like `my_fun(args)`.
+ /// A call expression, e.g., `my_fun(args)`.
Call(CallExpression),
+ /// A method call expression, e.g., `a.add(b)`.
+ Method(MethodCallExpression),
/// An expression of type "error".
/// Will result in a compile error eventually.
Err(ErrExpression),
@@ -63,6 +67,7 @@ impl Node for Expression {
Unary(n) => n.span(),
Ternary(n) => n.span(),
Call(n) => n.span(),
+ Method(n) => n.span(),
Err(n) => n.span(),
}
}
@@ -76,6 +81,7 @@ impl Node for Expression {
Unary(n) => n.set_span(span),
Ternary(n) => n.set_span(span),
Call(n) => n.set_span(span),
+ Method(n) => n.set_span(span),
Err(n) => n.set_span(span),
}
}
@@ -91,6 +97,7 @@ impl fmt::Display for Expression {
Unary(n) => n.fmt(f),
Ternary(n) => n.fmt(f),
Call(n) => n.fmt(f),
+ Method(n) => n.fmt(f),
Err(n) => n.fmt(f),
}
}
diff --git a/compiler/ast/src/passes/reconstructing_director.rs b/compiler/ast/src/passes/reconstructing_director.rs
index 78dd55bc0a..cd05767d33 100644
--- a/compiler/ast/src/passes/reconstructing_director.rs
+++ b/compiler/ast/src/passes/reconstructing_director.rs
@@ -46,6 +46,7 @@ impl ReconstructingDirector {
Expression::Unary(unary) => Expression::Unary(self.reduce_unary(unary)?),
Expression::Ternary(ternary) => Expression::Ternary(self.reduce_ternary(ternary)?),
Expression::Call(call) => Expression::Call(self.reduce_call(call)?),
+ Expression::Method(method) => Expression::Method(self.reduce_method(method)?),
Expression::Err(s) => Expression::Err(s.clone()),
};
@@ -106,6 +107,18 @@ impl ReconstructingDirector {
self.reducer.reduce_ternary(ternary, condition, if_true, if_false)
}
+ pub fn reduce_method(&mut self, method: &MethodCallExpression) -> Result {
+ let receiver = self.reduce_expression(&method.receiver)?;
+ let method_id = self.reduce_identifier(&method.method)?;
+
+ let mut arguments = vec![];
+ for argument in method.arguments.iter() {
+ arguments.push(self.reduce_expression(argument)?);
+ }
+
+ self.reducer.reduce_method(method, receiver, method_id, arguments)
+ }
+
pub fn reduce_call(&mut self, call: &CallExpression) -> Result {
let function = self.reduce_expression(&call.function)?;
diff --git a/compiler/ast/src/passes/reconstructing_reducer.rs b/compiler/ast/src/passes/reconstructing_reducer.rs
index f45dcdd62a..ede43d74e7 100644
--- a/compiler/ast/src/passes/reconstructing_reducer.rs
+++ b/compiler/ast/src/passes/reconstructing_reducer.rs
@@ -123,6 +123,21 @@ pub trait ReconstructingReducer {
})
}
+ fn reduce_method(
+ &mut self,
+ method: &MethodCallExpression,
+ receiver: Expression,
+ method_id: Identifier,
+ arguments: Vec,
+ ) -> Result {
+ Ok(MethodCallExpression {
+ receiver: Box::new(receiver),
+ method: method_id,
+ arguments,
+ span: method.span,
+ })
+ }
+
// Statements
fn reduce_statement(&mut self, _statement: &Statement, new: Statement) -> Result {
Ok(new)
diff --git a/compiler/ast/src/passes/visitor.rs b/compiler/ast/src/passes/visitor.rs
index 79c449cd3d..c41d8c0144 100644
--- a/compiler/ast/src/passes/visitor.rs
+++ b/compiler/ast/src/passes/visitor.rs
@@ -58,6 +58,10 @@ pub trait ExpressionVisitor<'a> {
Default::default()
}
+ fn visit_method(&mut self, _input: &'a MethodCallExpression) -> VisitResult {
+ Default::default()
+ }
+
fn visit_err(&mut self, _input: &'a ErrExpression) -> VisitResult {
Default::default()
}
diff --git a/compiler/ast/src/passes/visitor_director.rs b/compiler/ast/src/passes/visitor_director.rs
index 5ebe2bfd8d..d8b4a8641b 100644
--- a/compiler/ast/src/passes/visitor_director.rs
+++ b/compiler/ast/src/passes/visitor_director.rs
@@ -41,6 +41,7 @@ pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
Expression::Unary(expr) => self.visit_unary(expr, additional),
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
Expression::Call(expr) => self.visit_call(expr, additional),
+ Expression::Method(expr) => self.visit_method(expr, additional),
Expression::Err(expr) => self.visit_err(expr, additional),
};
}
@@ -99,6 +100,16 @@ pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
None
}
+ fn visit_method(&mut self, input: &'a MethodCallExpression, additional: &Self::AdditionalInput) -> Option {
+ self.visit_expression(&input.receiver, additional);
+ if let VisitResult::VisitChildren = self.visitor_ref().visit_method(input) {
+ input.arguments.iter().for_each(|expr| {
+ self.visit_expression(expr, additional);
+ });
+ }
+ None
+ }
+
fn visit_err(&mut self, input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Option {
self.visitor_ref().visit_err(input);
None
diff --git a/compiler/parser/src/parser/expression.rs b/compiler/parser/src/parser/expression.rs
index c01d374b1f..bb62bec9be 100644
--- a/compiler/parser/src/parser/expression.rs
+++ b/compiler/parser/src/parser/expression.rs
@@ -229,10 +229,24 @@ 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,
+ });
+ println!("expr {}", expr);
+ continue;
+ }
+ }
let curr = &self.token;
return Err(ParserError::unexpected_str(&curr.token, "int or ident", curr.span).into());
- }
+ }
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 097aaf85b6..6f954bc8ef 100644
--- a/compiler/passes/src/type_checker/check_expressions.rs
+++ b/compiler/passes/src/type_checker/check_expressions.rs
@@ -54,6 +54,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
Expression::Unary(expr) => self.visit_unary(expr, expected),
Expression::Ternary(expr) => self.visit_ternary(expr, expected),
Expression::Call(expr) => self.visit_call(expr, expected),
+ Expression::Method(expr) => self.visit_method(expr, expected),
Expression::Err(expr) => self.visit_err(expr, expected),
};
}
@@ -403,4 +404,38 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
expr => self.visit_expression(expr, expected),
}
}
+
+ fn visit_method(&mut self, input: &'a MethodCallExpression, expected: &Self::AdditionalInput) -> Option {
+ None
+ // input.receiver.
+ //
+ // if let Some(func) = self.visitor.symbol_table.clone().lookup_fn(&input.method.name) {
+ // let ret = self.visitor.assert_type(func.output, expected, func.span());
+ //
+ // if func.input.len() != input.arguments.len() {
+ // self.visitor.handler.emit_err(
+ // TypeCheckerError::incorrect_num_args_to_call(
+ // func.input.len(),
+ // input.arguments.len(),
+ // input.span(),
+ // )
+ // .into(),
+ // );
+ // }
+ //
+ // func.input
+ // .iter()
+ // .zip(input.arguments.iter())
+ // .for_each(|(expected, argument)| {
+ // self.visit_expression(argument, &Some(expected.get_variable().type_));
+ // });
+ //
+ // Some(ret)
+ // } else {
+ // self.visitor
+ // .handler
+ // .emit_err(TypeCheckerError::unknown_sym("method", &ident.name, ident.span()).into());
+ // None
+ // }
+ }
}
diff --git a/examples/hello-world/src/main.leo b/examples/hello-world/src/main.leo
index fef974c85e..c35404f1b3 100644
--- a/examples/hello-world/src/main.leo
+++ b/examples/hello-world/src/main.leo
@@ -1,4 +1,3 @@
-function main() -> bool {
- console.log("hello world");
- return true;
+function main(a: u8, b: u8) -> u8 {
+ return a.add(b);
}
\ No newline at end of file