impl method call expression parsing

This commit is contained in:
collin 2022-06-03 13:27:23 -04:00
parent 18b71d225b
commit f0a1573058
9 changed files with 149 additions and 5 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
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<Expression>,
/// The identifier of the called method.
pub method: Identifier,
/// Expressions for the arguments passed to the methods parameters.
pub arguments: Vec<Expression>,
/// 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);

View File

@ -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),
}
}

View File

@ -46,6 +46,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
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<R: ReconstructingReducer> ReconstructingDirector<R> {
self.reducer.reduce_ternary(ternary, condition, if_true, if_false)
}
pub fn reduce_method(&mut self, method: &MethodCallExpression) -> Result<MethodCallExpression> {
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<CallExpression> {
let function = self.reduce_expression(&call.function)?;

View File

@ -123,6 +123,21 @@ pub trait ReconstructingReducer {
})
}
fn reduce_method(
&mut self,
method: &MethodCallExpression,
receiver: Expression,
method_id: Identifier,
arguments: Vec<Expression>,
) -> Result<MethodCallExpression> {
Ok(MethodCallExpression {
receiver: Box::new(receiver),
method: method_id,
arguments,
span: method.span,
})
}
// Statements
fn reduce_statement(&mut self, _statement: &Statement, new: Statement) -> Result<Statement> {
Ok(new)

View File

@ -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()
}

View File

@ -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::Output> {
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::Output> {
self.visitor_ref().visit_err(input);
None

View File

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

View File

@ -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<Self::Output> {
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
// }
}
}

View File

@ -1,4 +1,3 @@
function main() -> bool {
console.log("hello world");
return true;
function main(a: u8, b: u8) -> u8 {
return a.add(b);
}