mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-19 15:41:36 +03:00
impl method call expression parsing
This commit is contained in:
parent
18b71d225b
commit
f0a1573058
46
compiler/ast/src/expression/method.rs
Normal file
46
compiler/ast/src/expression/method.rs
Normal 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);
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
function main() -> bool {
|
||||
console.log("hello world");
|
||||
return true;
|
||||
function main(a: u8, b: u8) -> u8 {
|
||||
return a.add(b);
|
||||
}
|
Loading…
Reference in New Issue
Block a user