parse method calls directly

This commit is contained in:
collin 2022-06-09 13:01:59 -07:00
parent df08cd1e26
commit a32418133c
5 changed files with 107 additions and 73 deletions

View File

@ -21,8 +21,10 @@ use super::*;
/// Precedence is defined in the parser. /// Precedence is defined in the parser.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinaryOperation { pub enum BinaryOperation {
/// Addition, i.e. `+`. /// Addition, i.e. `+`, `.add()`.
Add, Add,
/// Wrapped addition, i.e. `.add_wrapped()`.
AddWrapped,
/// Subtraction, i.e. `-`. /// Subtraction, i.e. `-`.
Sub, Sub,
/// Multiplication, i.e. `*`. /// Multiplication, i.e. `*`.
@ -61,41 +63,20 @@ pub enum BinaryOperationClass {
impl AsRef<str> for BinaryOperation { impl AsRef<str> for BinaryOperation {
fn as_ref(&self) -> &'static str { fn as_ref(&self) -> &'static str {
match self { match self {
BinaryOperation::Add => "+", BinaryOperation::Add => "add",
BinaryOperation::Sub => "-", BinaryOperation::AddWrapped => "add_wrapped",
BinaryOperation::Mul => "*", BinaryOperation::Sub => "sub",
BinaryOperation::Div => "/", BinaryOperation::Mul => "mul",
BinaryOperation::Pow => "**", BinaryOperation::Div => "div",
BinaryOperation::Or => "||", BinaryOperation::Pow => "pow",
BinaryOperation::And => "&&", BinaryOperation::Or => "or",
BinaryOperation::Eq => "==", BinaryOperation::And => "and",
BinaryOperation::Ne => "!=", BinaryOperation::Eq => "eq",
BinaryOperation::Ge => ">=", BinaryOperation::Ne => "ne",
BinaryOperation::Gt => ">", BinaryOperation::Ge => "ge",
BinaryOperation::Le => "<=", BinaryOperation::Gt => "gt",
BinaryOperation::Lt => "<", BinaryOperation::Le => "le",
} BinaryOperation::Lt => "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,
} }
} }
} }
@ -116,7 +97,7 @@ pub struct BinaryExpression {
impl fmt::Display for BinaryExpression { impl fmt::Display for BinaryExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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)
} }
} }

View File

@ -218,6 +218,48 @@ impl ParserContext<'_> {
Ok(inner) 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 /// Returns an [`Expression`] AST node if the next tokens represent an
/// array access, circuit member access, function call, or static function call expression. /// 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()?; let mut expr = self.parse_primary_expression()?;
loop { loop {
if self.eat(&Token::Dot) { if self.eat(&Token::Dot) {
// Handle method call expression. expr = self.parse_method_call_expression(expr)?
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());
} }
if !self.check(&Token::LeftParen) { if !self.check(&Token::LeftParen) {
break; break;

View File

@ -311,6 +311,13 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
Some(Type::Boolean) 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)
}
}; };
} }

View File

@ -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. /// 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) { pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span) self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)

View File

@ -100,30 +100,51 @@ macro_rules! symbols {
} }
symbols! { symbols! {
// unary operators
// binary operators
add,
add_w,
// arity three operators
// types
address, address,
AlwaysConst,
array, array,
assert,
bool, bool,
Class: "class",
context,
constants,
CoreFunction,
console,
Const: "const", Const: "const",
Constant, Constant,
Else: "else", constants,
error,
False: "false",
field, field,
For: "for",
function,
group, group,
i8, i8,
i16, i16,
i32, i32,
i64, i64,
i128, 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", If: "if",
In: "in", In: "in",
input, input,
@ -134,19 +155,11 @@ symbols! {
prelude, prelude,
Public, Public,
Return: "return", Return: "return",
scalar,
Star: "*", Star: "*",
std, std,
string,
Struct: "struct", Struct: "struct",
test, test,
True: "true",
Type: "type", Type: "type",
u8,
u16,
u32,
u64,
u128,
CONTAINER_PSEUDO_CIRCUIT: "$InputContainer", CONTAINER_PSEUDO_CIRCUIT: "$InputContainer",
REGISTERS_PSEUDO_CIRCUIT: "$InputRegister", REGISTERS_PSEUDO_CIRCUIT: "$InputRegister",
@ -154,11 +167,11 @@ symbols! {
STATE_PSEUDO_CIRCUIT: "$InputState", STATE_PSEUDO_CIRCUIT: "$InputState",
STATE_LEAF_PSEUDO_CIRCUIT: "$InputStateLeaf", STATE_LEAF_PSEUDO_CIRCUIT: "$InputStateLeaf",
// input file
registers, registers,
record, record,
state, state,
state_leaf, state_leaf,
public, public,
private, private,
} }