mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-28 20:54:16 +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
|
||||
/// a binary or expression.
|
||||
/// a binary OR expression.
|
||||
///
|
||||
/// Otherwise, tries to parse the next token using [`parse_conjunctive_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
|
||||
/// binary and expression.
|
||||
/// binary AND expression.
|
||||
///
|
||||
/// Otherwise, tries to parse the next token using [`parse_equality_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`.
|
||||
@ -132,6 +140,8 @@ impl ParserContext<'_> {
|
||||
Token::Or => BinaryOperation::Or,
|
||||
Token::And => BinaryOperation::And,
|
||||
Token::Exp => BinaryOperation::Pow,
|
||||
Token::Shl => BinaryOperation::Shl,
|
||||
Token::Shr => BinaryOperation::Shr,
|
||||
_ => unreachable!("`eat_bin_op` shouldn't produce this"),
|
||||
})
|
||||
}
|
||||
@ -218,6 +228,8 @@ impl ParserContext<'_> {
|
||||
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> {
|
||||
// Get the name of the method.
|
||||
if let Token::Ident(method) = self.token.token {
|
||||
|
@ -192,6 +192,24 @@ impl Token {
|
||||
(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.
|
||||
let twice = |input: &mut Peekable<_>, on, token| {
|
||||
input.next();
|
||||
@ -292,8 +310,14 @@ impl Token {
|
||||
}
|
||||
':' => return single(&mut input, Token::Colon),
|
||||
';' => return single(&mut input, Token::Semicolon),
|
||||
'<' => return followed_by(&mut input, '=', Token::LtEq, Token::Lt),
|
||||
'>' => return followed_by(&mut input, '=', Token::GtEq, Token::Gt),
|
||||
'<' => return three_cases(&mut input,
|
||||
'=', 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 single(&mut input, Token::LeftSquare),
|
||||
']' => return single(&mut input, Token::RightSquare),
|
||||
|
@ -63,6 +63,8 @@ pub enum Token {
|
||||
Colon,
|
||||
Question,
|
||||
Arrow,
|
||||
Shl,
|
||||
Shr,
|
||||
Underscore,
|
||||
|
||||
// Syntactic Grammar
|
||||
@ -221,6 +223,8 @@ impl fmt::Display for Token {
|
||||
Colon => write!(f, ":"),
|
||||
Question => write!(f, "?"),
|
||||
Arrow => write!(f, "->"),
|
||||
Shl => write!(f, "<<"),
|
||||
Shr => write!(f, ">>"),
|
||||
Underscore => write!(f, "_"),
|
||||
|
||||
Address => write!(f, "address"),
|
||||
|
@ -258,45 +258,38 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Pow => {
|
||||
self.visitor.assert_field_int_type(expected, input.span());
|
||||
|
||||
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()) {
|
||||
// Type A must be an int.
|
||||
// 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(_))) => {
|
||||
(Some(Type::Field), Some(other)) => {
|
||||
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.
|
||||
// But Type B was not an int.
|
||||
(Some(Type::Field), Some(t)) => {
|
||||
self.visitor.handler.emit_err(
|
||||
TypeCheckerError::incorrect_pow_exponent_type("int", t, input.right.span()).into(),
|
||||
);
|
||||
(Some(other), Some(Type::Field)) => {
|
||||
self.visitor.assert_type(*other, &Some(Type::Field), input.left.span());
|
||||
self.visitor.assert_type(Type::Field, expected, input.right.span());
|
||||
Some(Type::Field)
|
||||
}
|
||||
// The base is some type thats not an int or field.
|
||||
(Some(t), _) if !matches!(t, Type::IntegerType(_) | Type::Field) => {
|
||||
self.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::incorrect_pow_base_type(t, input.left.span()).into());
|
||||
(Some(t1), Some(t2)) => {
|
||||
// Allow integer exponentiation.
|
||||
self.visitor.assert_type(*t1, expected, input.left.span());
|
||||
self.visitor.assert_type(*t2, expected, input.right.span());
|
||||
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 => {
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
@ -320,8 +313,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
BinaryOperation::AddWrapped
|
||||
| BinaryOperation::SubWrapped
|
||||
| BinaryOperation::DivWrapped
|
||||
| BinaryOperation::MulWrapped
|
||||
| BinaryOperation::PowWrapped => {
|
||||
| BinaryOperation::MulWrapped => {
|
||||
self.visitor.assert_int_type(expected, input.span);
|
||||
let t1 = self.visit_expression(&input.left, expected);
|
||||
let t2 = self.visit_expression(&input.right, expected);
|
||||
@ -331,11 +323,13 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
BinaryOperation::Shl
|
||||
| BinaryOperation::ShlWrapped
|
||||
| BinaryOperation::Shr
|
||||
| BinaryOperation::ShrWrapped => {
|
||||
// todo @collinc97: add magnitude check for second operand (u8, u16, u32).
|
||||
| BinaryOperation::ShrWrapped
|
||||
| BinaryOperation::PowWrapped => {
|
||||
self.visitor.assert_int_type(expected, input.span);
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -45,6 +45,12 @@ const INT_TYPES: [Type; 10] = [
|
||||
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>(
|
||||
subset: [Type; S],
|
||||
additional: [Type; A],
|
||||
@ -148,6 +154,11 @@ impl<'a> TypeChecker<'a> {
|
||||
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.
|
||||
pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
|
@ -1,3 +1,3 @@
|
||||
function main(a: u8, b: u8) -> u8 {
|
||||
return a.add_wrapped(b);
|
||||
function main(a: u8) -> u8 {
|
||||
return a >> 1u32;
|
||||
}
|
Loading…
Reference in New Issue
Block a user