mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-18 14:31:31 +03:00
parse method calls directly
This commit is contained in:
parent
df08cd1e26
commit
a32418133c
@ -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<str> 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,6 +218,48 @@ impl ParserContext<'_> {
|
||||
Ok(inner)
|
||||
}
|
||||
|
||||
fn parse_method_call_expression(&mut self, receiver: Expression) -> Result<Expression> {
|
||||
// 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;
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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<Type>, 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<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user