mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-29 13:14:05 +03:00
impl shl shr tokens and type checking
This commit is contained in:
parent
4e3ed8d4dc
commit
32f0c96b6f
@ -101,7 +101,7 @@ impl ParserContext<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Expression`] AST node if the next tokens represent
|
/// Returns an [`Expression`] AST node if the next tokens represent
|
||||||
/// a binary or expression.
|
/// a binary OR expression.
|
||||||
///
|
///
|
||||||
/// Otherwise, tries to parse the next token using [`parse_conjunctive_expression`].
|
/// Otherwise, tries to parse the next token using [`parse_conjunctive_expression`].
|
||||||
fn parse_disjunctive_expression(&mut self) -> Result<Expression> {
|
fn parse_disjunctive_expression(&mut self) -> Result<Expression> {
|
||||||
@ -109,11 +109,19 @@ impl ParserContext<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||||
/// binary and expression.
|
/// binary AND expression.
|
||||||
///
|
///
|
||||||
/// Otherwise, tries to parse the next token using [`parse_equality_expression`].
|
/// Otherwise, tries to parse the next token using [`parse_equality_expression`].
|
||||||
fn parse_conjunctive_expression(&mut self) -> Result<Expression> {
|
fn parse_conjunctive_expression(&mut self) -> Result<Expression> {
|
||||||
self.parse_bin_expr(&[Token::And], Self::parse_equality_expression)
|
self.parse_bin_expr(&[Token::And], Self::parse_shift_expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||||
|
/// shift left or a shift right expression.
|
||||||
|
///
|
||||||
|
/// Otherwise, tries to parse the next token using [`parse_equality_expression`].
|
||||||
|
fn parse_shift_expression(&mut self) -> Result<Expression> {
|
||||||
|
self.parse_bin_expr(&[Token::Shl, Token::Shr], Self::parse_equality_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eats one of binary operators matching any in `tokens`.
|
/// Eats one of binary operators matching any in `tokens`.
|
||||||
@ -132,6 +140,8 @@ impl ParserContext<'_> {
|
|||||||
Token::Or => BinaryOperation::Or,
|
Token::Or => BinaryOperation::Or,
|
||||||
Token::And => BinaryOperation::And,
|
Token::And => BinaryOperation::And,
|
||||||
Token::Exp => BinaryOperation::Pow,
|
Token::Exp => BinaryOperation::Pow,
|
||||||
|
Token::Shl => BinaryOperation::Shl,
|
||||||
|
Token::Shr => BinaryOperation::Shr,
|
||||||
_ => unreachable!("`eat_bin_op` shouldn't produce this"),
|
_ => unreachable!("`eat_bin_op` shouldn't produce this"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -218,6 +228,8 @@ impl ParserContext<'_> {
|
|||||||
Ok(inner)
|
Ok(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||||
|
/// method call expression.
|
||||||
fn parse_method_call_expression(&mut self, receiver: Expression) -> Result<Expression> {
|
fn parse_method_call_expression(&mut self, receiver: Expression) -> Result<Expression> {
|
||||||
// Get the name of the method.
|
// Get the name of the method.
|
||||||
if let Token::Ident(method) = self.token.token {
|
if let Token::Ident(method) = self.token.token {
|
||||||
|
@ -192,6 +192,24 @@ impl Token {
|
|||||||
(1, els)
|
(1, els)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
// Consumes a character followed by `on_1`, `on_2` or none. Outputs case_1, case_2, or els.
|
||||||
|
let three_cases = |
|
||||||
|
input: &mut Peekable<_>,
|
||||||
|
on_1,
|
||||||
|
case_1,
|
||||||
|
on_2,
|
||||||
|
case_2,
|
||||||
|
els
|
||||||
|
| {
|
||||||
|
input.next();
|
||||||
|
Ok(if input.next_if_eq(&on_1).is_some() {
|
||||||
|
(2, case_1)
|
||||||
|
} else if input.next_if_eq(&on_2).is_some() {
|
||||||
|
(2, case_2)
|
||||||
|
} else {
|
||||||
|
(1, els)
|
||||||
|
})
|
||||||
|
};
|
||||||
// Consumes `on` again and produces `token` if found.
|
// Consumes `on` again and produces `token` if found.
|
||||||
let twice = |input: &mut Peekable<_>, on, token| {
|
let twice = |input: &mut Peekable<_>, on, token| {
|
||||||
input.next();
|
input.next();
|
||||||
@ -292,8 +310,14 @@ impl Token {
|
|||||||
}
|
}
|
||||||
':' => return single(&mut input, Token::Colon),
|
':' => return single(&mut input, Token::Colon),
|
||||||
';' => return single(&mut input, Token::Semicolon),
|
';' => return single(&mut input, Token::Semicolon),
|
||||||
'<' => return followed_by(&mut input, '=', Token::LtEq, Token::Lt),
|
'<' => return three_cases(&mut input,
|
||||||
'>' => return followed_by(&mut input, '=', Token::GtEq, Token::Gt),
|
'=', Token::LtEq,
|
||||||
|
'<', Token::Shl,
|
||||||
|
Token::Lt),
|
||||||
|
'>' => return three_cases(&mut input,
|
||||||
|
'=', Token::GtEq,
|
||||||
|
'>', Token::Shr,
|
||||||
|
Token::Gt),
|
||||||
'=' => return followed_by(&mut input, '=', Token::Eq, Token::Assign),
|
'=' => return followed_by(&mut input, '=', Token::Eq, Token::Assign),
|
||||||
'[' => return single(&mut input, Token::LeftSquare),
|
'[' => return single(&mut input, Token::LeftSquare),
|
||||||
']' => return single(&mut input, Token::RightSquare),
|
']' => return single(&mut input, Token::RightSquare),
|
||||||
|
@ -63,6 +63,8 @@ pub enum Token {
|
|||||||
Colon,
|
Colon,
|
||||||
Question,
|
Question,
|
||||||
Arrow,
|
Arrow,
|
||||||
|
Shl,
|
||||||
|
Shr,
|
||||||
Underscore,
|
Underscore,
|
||||||
|
|
||||||
// Syntactic Grammar
|
// Syntactic Grammar
|
||||||
@ -221,6 +223,8 @@ impl fmt::Display for Token {
|
|||||||
Colon => write!(f, ":"),
|
Colon => write!(f, ":"),
|
||||||
Question => write!(f, "?"),
|
Question => write!(f, "?"),
|
||||||
Arrow => write!(f, "->"),
|
Arrow => write!(f, "->"),
|
||||||
|
Shl => write!(f, "<<"),
|
||||||
|
Shr => write!(f, ">>"),
|
||||||
Underscore => write!(f, "_"),
|
Underscore => write!(f, "_"),
|
||||||
|
|
||||||
Address => write!(f, "address"),
|
Address => write!(f, "address"),
|
||||||
|
@ -258,45 +258,38 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
|||||||
return_incorrect_type(t1, t2, expected)
|
return_incorrect_type(t1, t2, expected)
|
||||||
}
|
}
|
||||||
BinaryOperation::Pow => {
|
BinaryOperation::Pow => {
|
||||||
|
self.visitor.assert_field_int_type(expected, input.span());
|
||||||
|
|
||||||
let t1 = self.visit_expression(&input.left, &None);
|
let t1 = self.visit_expression(&input.left, &None);
|
||||||
let t2 = self.visit_expression(&input.right, &None);
|
let t2 = self.visit_expression(&input.left, &None);
|
||||||
|
|
||||||
match (t1.as_ref(), t2.as_ref()) {
|
match (t1.as_ref(), t2.as_ref()) {
|
||||||
// Type A must be an int.
|
(Some(Type::Field), Some(other)) => {
|
||||||
// Type B must be a unsigned int.
|
|
||||||
(Some(Type::IntegerType(_)), Some(Type::IntegerType(itype))) if !itype.is_signed() => {
|
|
||||||
self.visitor.assert_type(t1.unwrap(), expected, input.left.span());
|
|
||||||
}
|
|
||||||
// Type A was an int.
|
|
||||||
// But Type B was not a unsigned int.
|
|
||||||
(Some(Type::IntegerType(_)), Some(t)) => {
|
|
||||||
self.visitor.handler.emit_err(
|
|
||||||
TypeCheckerError::incorrect_pow_exponent_type("unsigned int", t, input.right.span())
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Type A must be a field.
|
|
||||||
// Type B must be an int.
|
|
||||||
(Some(Type::Field), Some(Type::IntegerType(_))) => {
|
|
||||||
self.visitor.assert_type(Type::Field, expected, input.left.span());
|
self.visitor.assert_type(Type::Field, expected, input.left.span());
|
||||||
|
self.visitor.assert_type(*other, &Some(Type::Field), input.left.span());
|
||||||
|
Some(Type::Field)
|
||||||
}
|
}
|
||||||
// Type A was a field.
|
(Some(other), Some(Type::Field)) => {
|
||||||
// But Type B was not an int.
|
self.visitor.assert_type(*other, &Some(Type::Field), input.left.span());
|
||||||
(Some(Type::Field), Some(t)) => {
|
self.visitor.assert_type(Type::Field, expected, input.right.span());
|
||||||
self.visitor.handler.emit_err(
|
Some(Type::Field)
|
||||||
TypeCheckerError::incorrect_pow_exponent_type("int", t, input.right.span()).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// The base is some type thats not an int or field.
|
(Some(t1), Some(t2)) => {
|
||||||
(Some(t), _) if !matches!(t, Type::IntegerType(_) | Type::Field) => {
|
// Allow integer exponentiation.
|
||||||
self.visitor
|
self.visitor.assert_type(*t1, expected, input.left.span());
|
||||||
.handler
|
self.visitor.assert_type(*t2, expected, input.right.span());
|
||||||
.emit_err(TypeCheckerError::incorrect_pow_base_type(t, input.left.span()).into());
|
return_incorrect_type(Some(*t1), Some(*t2), expected)
|
||||||
}
|
}
|
||||||
_ => {}
|
(Some(type_), None) => {
|
||||||
|
self.visitor.assert_type(*type_, expected, input.left.span());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(None, Some(type_)) => {
|
||||||
|
self.visitor.assert_type(*type_, expected, input.right.span());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(None, None) => None,
|
||||||
}
|
}
|
||||||
|
|
||||||
t1
|
|
||||||
}
|
}
|
||||||
BinaryOperation::Eq | BinaryOperation::Neq => {
|
BinaryOperation::Eq | BinaryOperation::Neq => {
|
||||||
let t1 = self.visit_expression(&input.left, &None);
|
let t1 = self.visit_expression(&input.left, &None);
|
||||||
@ -320,8 +313,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
|||||||
BinaryOperation::AddWrapped
|
BinaryOperation::AddWrapped
|
||||||
| BinaryOperation::SubWrapped
|
| BinaryOperation::SubWrapped
|
||||||
| BinaryOperation::DivWrapped
|
| BinaryOperation::DivWrapped
|
||||||
| BinaryOperation::MulWrapped
|
| BinaryOperation::MulWrapped => {
|
||||||
| BinaryOperation::PowWrapped => {
|
|
||||||
self.visitor.assert_int_type(expected, input.span);
|
self.visitor.assert_int_type(expected, input.span);
|
||||||
let t1 = self.visit_expression(&input.left, expected);
|
let t1 = self.visit_expression(&input.left, expected);
|
||||||
let t2 = self.visit_expression(&input.right, expected);
|
let t2 = self.visit_expression(&input.right, expected);
|
||||||
@ -331,11 +323,13 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
|||||||
BinaryOperation::Shl
|
BinaryOperation::Shl
|
||||||
| BinaryOperation::ShlWrapped
|
| BinaryOperation::ShlWrapped
|
||||||
| BinaryOperation::Shr
|
| BinaryOperation::Shr
|
||||||
| BinaryOperation::ShrWrapped => {
|
| BinaryOperation::ShrWrapped
|
||||||
// todo @collinc97: add magnitude check for second operand (u8, u16, u32).
|
| BinaryOperation::PowWrapped => {
|
||||||
self.visitor.assert_int_type(expected, input.span);
|
self.visitor.assert_int_type(expected, input.span);
|
||||||
|
|
||||||
let t1 = self.visit_expression(&input.left, expected);
|
let t1 = self.visit_expression(&input.left, expected);
|
||||||
let t2 = self.visit_expression(&input.right, expected);
|
let t2 = self.visit_expression(&input.left, &None);
|
||||||
|
self.visitor.assert_magnitude_type(&t2, input.right.span());
|
||||||
|
|
||||||
return_incorrect_type(t1, t2, expected)
|
return_incorrect_type(t1, t2, expected)
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,12 @@ const INT_TYPES: [Type; 10] = [
|
|||||||
Type::IntegerType(IntegerType::U128),
|
Type::IntegerType(IntegerType::U128),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const MAGNITUDE_TYPES: [Type; 3] = [
|
||||||
|
Type::IntegerType(IntegerType::U8),
|
||||||
|
Type::IntegerType(IntegerType::U16),
|
||||||
|
Type::IntegerType(IntegerType::U32),
|
||||||
|
];
|
||||||
|
|
||||||
const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
|
const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
|
||||||
subset: [Type; S],
|
subset: [Type; S],
|
||||||
additional: [Type; A],
|
additional: [Type; A],
|
||||||
@ -148,6 +154,11 @@ impl<'a> TypeChecker<'a> {
|
|||||||
self.assert_one_of_types(type_, &INT_TYPES, span)
|
self.assert_one_of_types(type_, &INT_TYPES, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
|
||||||
|
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||||
|
self.assert_one_of_types(type_, &MAGNITUDE_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)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
function main(a: u8, b: u8) -> u8 {
|
function main(a: u8) -> u8 {
|
||||||
return a.add_wrapped(b);
|
return a >> 1u32;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user