Add div/mod parsing
This commit is contained in:
		
							parent
							
								
									691c91504b
								
							
						
					
					
						commit
						b9459a19bb
					
				| @ -46,11 +46,16 @@ Currently missing big features (TODOs) are: | |||||||
| - Loops | - Loops | ||||||
| - Debug Information (PARTIALLY DONE) | - Debug Information (PARTIALLY DONE) | ||||||
| - Ability to specify types in literals and variable definitions | - Ability to specify types in literals and variable definitions | ||||||
|  | - Intrinsic functions | ||||||
|  | - Not-Unary | ||||||
| 
 | 
 | ||||||
| Big features that I want later but are not necessary: | Big features that I want later but are not necessary: | ||||||
| - Associated functions | - Associated functions | ||||||
| - User-defined binary operations | - User-defined binary operations | ||||||
| - Asymmetric binary operations (e.g. string + u32) | - Asymmetric binary operations (e.g. string + u32) | ||||||
|  | - Error handling | ||||||
|  | - Lexing & parsing of whitespace and comments as well | ||||||
|  | - LSP implementation | ||||||
| 
 | 
 | ||||||
| Smaller features: | Smaller features: | ||||||
| - Hex-numbers | - Hex-numbers | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								examples/div_mod.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								examples/div_mod.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | // Arithmetic, function calls and imports! | ||||||
|  | 
 | ||||||
|  | fn main() -> u16 { | ||||||
|  | 
 | ||||||
|  |   return (50 / 5 + 52 % 5); | ||||||
|  | } | ||||||
| @ -81,6 +81,8 @@ pub enum BinaryOperator { | |||||||
|     Add, |     Add, | ||||||
|     Minus, |     Minus, | ||||||
|     Mult, |     Mult, | ||||||
|  |     Div, | ||||||
|  |     Mod, | ||||||
| 
 | 
 | ||||||
|     And, |     And, | ||||||
|     LT, |     LT, | ||||||
| @ -95,9 +97,11 @@ impl BinaryOperator { | |||||||
|     pub fn get_precedence(&self) -> i8 { |     pub fn get_precedence(&self) -> i8 { | ||||||
|         use BinaryOperator::*; |         use BinaryOperator::*; | ||||||
|         match &self { |         match &self { | ||||||
|  |             Minus => 5, | ||||||
|             Add => 10, |             Add => 10, | ||||||
|             Minus => 10, |             Mult => 15, | ||||||
|             Mult => 20, |             Div => 20, | ||||||
|  |             Mod => 20, | ||||||
|             And => 100, |             And => 100, | ||||||
|             LT => 100, |             LT => 100, | ||||||
|             LE => 100, |             LE => 100, | ||||||
|  | |||||||
| @ -350,6 +350,8 @@ impl Parse for BinaryOperator { | |||||||
|             (Some(Token::Plus), _) => BinaryOperator::Add, |             (Some(Token::Plus), _) => BinaryOperator::Add, | ||||||
|             (Some(Token::Minus), _) => BinaryOperator::Minus, |             (Some(Token::Minus), _) => BinaryOperator::Minus, | ||||||
|             (Some(Token::Star), _) => BinaryOperator::Mult, |             (Some(Token::Star), _) => BinaryOperator::Mult, | ||||||
|  |             (Some(Token::Slash), _) => BinaryOperator::Div, | ||||||
|  |             (Some(Token::Percent), _) => BinaryOperator::Mod, | ||||||
|             (_, _) => Err(stream.expected_err("expected operator")?)?, |             (_, _) => Err(stream.expected_err("expected operator")?)?, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -286,6 +286,8 @@ impl ast::BinaryOperator { | |||||||
|             ast::BinaryOperator::Minus => mir::BinaryOperator::Minus, |             ast::BinaryOperator::Minus => mir::BinaryOperator::Minus, | ||||||
|             ast::BinaryOperator::Mult => mir::BinaryOperator::Mult, |             ast::BinaryOperator::Mult => mir::BinaryOperator::Mult, | ||||||
|             ast::BinaryOperator::And => mir::BinaryOperator::And, |             ast::BinaryOperator::And => mir::BinaryOperator::And, | ||||||
|  |             ast::BinaryOperator::Div => mir::BinaryOperator::Div, | ||||||
|  |             ast::BinaryOperator::Mod => mir::BinaryOperator::Mod, | ||||||
|             ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT), |             ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT), | ||||||
|             ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE), |             ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE), | ||||||
|             ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT), |             ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT), | ||||||
|  | |||||||
| @ -659,6 +659,14 @@ impl mir::Expression { | |||||||
|                     (mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs), |                     (mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs), | ||||||
|                     (mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs), |                     (mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs), | ||||||
|                     (mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs), |                     (mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs), | ||||||
|  |                     (mir::BinaryOperator::Div, true, true) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Div, true, false) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Div, false, true) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Div, false, false) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Mod, true, true) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Mod, true, false) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Mod, false, true) => todo!(), | ||||||
|  |                     (mir::BinaryOperator::Mod, false, false) => todo!(), | ||||||
|                 }; |                 }; | ||||||
|                 Some(StackValue( |                 Some(StackValue( | ||||||
|                     StackValueKind::Immutable(scope.block.build(instr).unwrap()), |                     StackValueKind::Immutable(scope.block.build(instr).unwrap()), | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ use std::{fmt::Debug, str::Chars}; | |||||||
| 
 | 
 | ||||||
| static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; | static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)] | #[derive(Eq, PartialEq, Clone, PartialOrd, Ord)] | ||||||
| pub enum Token { | pub enum Token { | ||||||
|     /// Values
 |     /// Values
 | ||||||
|     Identifier(String), |     Identifier(String), | ||||||
| @ -56,6 +56,10 @@ pub enum Token { | |||||||
|     Star, |     Star, | ||||||
|     /// `-`
 |     /// `-`
 | ||||||
|     Minus, |     Minus, | ||||||
|  |     /// `/`
 | ||||||
|  |     Slash, | ||||||
|  |     /// `%`
 | ||||||
|  |     Percent, | ||||||
| 
 | 
 | ||||||
|     /// `>`
 |     /// `>`
 | ||||||
|     GreaterThan, |     GreaterThan, | ||||||
| @ -83,6 +87,8 @@ pub enum Token { | |||||||
|     /// `.`
 |     /// `.`
 | ||||||
|     Dot, |     Dot, | ||||||
| 
 | 
 | ||||||
|  |     Unknown(char), | ||||||
|  | 
 | ||||||
|     Eof, |     Eof, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -149,6 +155,18 @@ impl ToString for Token { | |||||||
|             Token::Comma => String::from(','), |             Token::Comma => String::from(','), | ||||||
|             Token::Dot => String::from('.'), |             Token::Dot => String::from('.'), | ||||||
|             Token::Eof => String::new(), |             Token::Eof => String::new(), | ||||||
|  |             Token::Slash => String::from('/'), | ||||||
|  |             Token::Percent => String::from('%'), | ||||||
|  |             Token::Unknown(val) => val.to_string(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl std::fmt::Debug for Token { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |         match self { | ||||||
|  |             Self::Unknown(value) => write!(f, "Unknown(\'{}\')", value.to_string()), | ||||||
|  |             _ => write!(f, "{}", self.to_string()), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -163,7 +181,7 @@ pub struct FullToken { | |||||||
| impl Debug for FullToken { | impl Debug for FullToken { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         f.write_fmt(format_args!( |         f.write_fmt(format_args!( | ||||||
|             "{:?} (Ln {}, Col {})", |             "Token({:?}) (Ln {}, Col {})", | ||||||
|             self.token, self.position.1, self.position.0 |             self.token, self.position.1, self.position.0 | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
| @ -343,8 +361,10 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | |||||||
|             '}' => Token::BraceClose, |             '}' => Token::BraceClose, | ||||||
|             ',' => Token::Comma, |             ',' => Token::Comma, | ||||||
|             '.' => Token::Dot, |             '.' => Token::Dot, | ||||||
|             // Invalid token
 |             '/' => Token::Slash, | ||||||
|             _ => Err(Error::InvalidToken(*character, cursor.position))?, |             '%' => Token::Percent, | ||||||
|  |             // Unknown token
 | ||||||
|  |             value => Token::Unknown(*value), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         tokens.push(FullToken { |         tokens.push(FullToken { | ||||||
|  | |||||||
| @ -299,6 +299,8 @@ impl Display for BinaryOperator { | |||||||
|             BinaryOperator::Mult => write!(f, "*"), |             BinaryOperator::Mult => write!(f, "*"), | ||||||
|             BinaryOperator::And => write!(f, "&&"), |             BinaryOperator::And => write!(f, "&&"), | ||||||
|             BinaryOperator::Cmp(op) => Display::fmt(op, f), |             BinaryOperator::Cmp(op) => Display::fmt(op, f), | ||||||
|  |             BinaryOperator::Div => write!(f, "/"), | ||||||
|  |             BinaryOperator::Mod => write!(f, "%"), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -104,14 +104,20 @@ impl TypeKind { | |||||||
|             BinaryOperator::Mult => self.clone(), |             BinaryOperator::Mult => self.clone(), | ||||||
|             BinaryOperator::And => TypeKind::Bool, |             BinaryOperator::And => TypeKind::Bool, | ||||||
|             BinaryOperator::Cmp(_) => TypeKind::Bool, |             BinaryOperator::Cmp(_) => TypeKind::Bool, | ||||||
|  |             BinaryOperator::Div => self.clone(), | ||||||
|  |             BinaryOperator::Mod => self.clone(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Reverse of binop_type, where the given hint is the known required output
 | ||||||
|  |     /// type of the binop, and the output is the hint for the lhs/rhs type.
 | ||||||
|     pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { |     pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { | ||||||
|         match op { |         match op { | ||||||
|             BinaryOperator::Add | BinaryOperator::Minus | BinaryOperator::Mult => { |             BinaryOperator::Add | ||||||
|                 Some(self.clone()) |             | BinaryOperator::Minus | ||||||
|             } |             | BinaryOperator::Mult | ||||||
|  |             | BinaryOperator::Div | ||||||
|  |             | BinaryOperator::Mod => Some(self.clone()), | ||||||
|             BinaryOperator::And => None, |             BinaryOperator::And => None, | ||||||
|             BinaryOperator::Cmp(_) => None, |             BinaryOperator::Cmp(_) => None, | ||||||
|         } |         } | ||||||
| @ -465,12 +471,16 @@ impl Expression { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn is_zero(&self) -> Option<bool> { |     pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> { | ||||||
|         Some(self.num_value()? == 0) |         if let Some(val) = self.num_value()? { | ||||||
|  |             Ok(Some(val == 0)) | ||||||
|  |         } else { | ||||||
|  |             Ok(None) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn num_value(&self) -> Option<i128> { |     pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> { | ||||||
|         match &self.0 { |         Ok(match &self.0 { | ||||||
|             ExprKind::Variable(_) => None, |             ExprKind::Variable(_) => None, | ||||||
|             ExprKind::Indexed(..) => None, |             ExprKind::Indexed(..) => None, | ||||||
|             ExprKind::Accessed(..) => None, |             ExprKind::Accessed(..) => None, | ||||||
| @ -478,22 +488,46 @@ impl Expression { | |||||||
|             ExprKind::Struct(..) => None, |             ExprKind::Struct(..) => None, | ||||||
|             ExprKind::Literal(literal) => literal.num_value(), |             ExprKind::Literal(literal) => literal.num_value(), | ||||||
|             ExprKind::BinOp(op, lhs, rhs) => match op { |             ExprKind::BinOp(op, lhs, rhs) => match op { | ||||||
|                 BinaryOperator::Add => Some(lhs.num_value()? + rhs.num_value()?), |                 BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b), | ||||||
|                 BinaryOperator::Minus => Some(lhs.num_value()? - rhs.num_value()?), |                 BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b), | ||||||
|                 BinaryOperator::Mult => Some(lhs.num_value()? * rhs.num_value()?), |                 BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b), | ||||||
|                 BinaryOperator::And => None, |                 BinaryOperator::And => None, | ||||||
|                 BinaryOperator::Cmp(_) => None, |                 BinaryOperator::Cmp(_) => None, | ||||||
|  |                 BinaryOperator::Div => { | ||||||
|  |                     let rhs_value = rhs.num_value()?; | ||||||
|  |                     if rhs_value == Some(0) { | ||||||
|  |                         Err(ErrorKind::DivideZero)? | ||||||
|  |                     } | ||||||
|  |                     maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b) | ||||||
|  |                 } | ||||||
|  |                 BinaryOperator::Mod => { | ||||||
|  |                     let rhs_value = rhs.num_value()?; | ||||||
|  |                     if rhs_value == Some(0) { | ||||||
|  |                         Err(ErrorKind::DivideZero)? | ||||||
|  |                     } | ||||||
|  |                     maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b) | ||||||
|  |                 } | ||||||
|             }, |             }, | ||||||
|             ExprKind::FunctionCall(..) => None, |             ExprKind::FunctionCall(..) => None, | ||||||
|             ExprKind::If(_) => None, |             ExprKind::If(_) => None, | ||||||
|             ExprKind::Block(_) => None, |             ExprKind::Block(_) => None, | ||||||
|             ExprKind::Borrow(_, _) => None, |             ExprKind::Borrow(_, _) => None, | ||||||
|             ExprKind::Deref(_) => None, |             ExprKind::Deref(_) => None, | ||||||
|             ExprKind::CastTo(expression, _) => expression.num_value(), |             ExprKind::CastTo(expression, _) => expression.num_value()?, | ||||||
|         } |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn maybe<T>(lhs: Option<i128>, rhs: Option<i128>, fun: T) -> Option<i128> | ||||||
|  | where | ||||||
|  |     T: FnOnce(i128, i128) -> i128, | ||||||
|  | { | ||||||
|  |     if let (Some(lhs), Some(rhs)) = (lhs, rhs) { | ||||||
|  |         Some(fun(lhs, rhs)) | ||||||
|  |     } else { | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | } | ||||||
| impl IfExpression { | impl IfExpression { | ||||||
|     pub fn return_type( |     pub fn return_type( | ||||||
|         &self, |         &self, | ||||||
|  | |||||||
| @ -218,6 +218,8 @@ pub enum BinaryOperator { | |||||||
|     Add, |     Add, | ||||||
|     Minus, |     Minus, | ||||||
|     Mult, |     Mult, | ||||||
|  |     Div, | ||||||
|  |     Mod, | ||||||
|     And, |     And, | ||||||
|     Cmp(CmpOperator), |     Cmp(CmpOperator), | ||||||
| } | } | ||||||
|  | |||||||
| @ -68,6 +68,8 @@ pub enum ErrorKind { | |||||||
|     NegativeUnsignedValue(TypeKind), |     NegativeUnsignedValue(TypeKind), | ||||||
|     #[error("Cannot cast type {0} into type {1}!")] |     #[error("Cannot cast type {0} into type {1}!")] | ||||||
|     NotCastableTo(TypeKind, TypeKind), |     NotCastableTo(TypeKind, TypeKind), | ||||||
|  |     #[error("Cannot divide by zero")] | ||||||
|  |     DivideZero, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | /// Struct used to implement a type-checking pass that can be performed on the
 | ||||||
| @ -426,7 +428,7 @@ impl Expression { | |||||||
|                 let both_t = lhs_type.collapse_into(&rhs_type)?; |                 let both_t = lhs_type.collapse_into(&rhs_type)?; | ||||||
| 
 | 
 | ||||||
|                 if *op == BinaryOperator::Minus && !lhs_type.signed() { |                 if *op == BinaryOperator::Minus && !lhs_type.signed() { | ||||||
|                     if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value(), rhs.num_value()) { |                     if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?) { | ||||||
|                         if lhs_val < rhs_val { |                         if lhs_val < rhs_val { | ||||||
|                             return Err(ErrorKind::NegativeUnsignedValue(lhs_type)); |                             return Err(ErrorKind::NegativeUnsignedValue(lhs_type)); | ||||||
|                         } |                         } | ||||||
|  | |||||||
| @ -235,7 +235,7 @@ impl std::iter::Sum for TokenRange { | |||||||
| 
 | 
 | ||||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||||
| pub enum Error { | pub enum Error { | ||||||
|     #[error("Expected {} got \"{}\"", .0, .1.to_string())] |     #[error("Expected {} got \"{:?}\"", .0, .1)] | ||||||
|     Expected(String, Token, TokenRange), |     Expected(String, Token, TokenRange), | ||||||
|     #[error("Source file contains no tokens")] |     #[error("Source file contains no tokens")] | ||||||
|     FileEmpty, |     FileEmpty, | ||||||
|  | |||||||
| @ -18,15 +18,15 @@ fn test(source: &str, name: &str) { | |||||||
|     )); |     )); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub static ARRAY: &str = include_str!("../../reid_src/array.reid"); | pub static ARRAY: &str = include_str!("../../examples/array.reid"); | ||||||
| pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid"); | pub static FIBONACCI: &str = include_str!("../../examples/fibonacci.reid"); | ||||||
| pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid"); | pub static HELLO_WORLD: &str = include_str!("../../examples/hello_world.reid"); | ||||||
| pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid"); | pub static MUTABLE: &str = include_str!("../../examples/mutable.reid"); | ||||||
| pub static STRINGS: &str = include_str!("../../reid_src/strings.reid"); | pub static STRINGS: &str = include_str!("../../examples/strings.reid"); | ||||||
| pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid"); | pub static STRUCTS: &str = include_str!("../../examples/struct.reid"); | ||||||
| pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid"); | pub static ARRAY_STRUCTS: &str = include_str!("../../examples/array_structs.reid"); | ||||||
| pub static BORROW: &str = include_str!("../../reid_src/borrow.reid"); | pub static BORROW: &str = include_str!("../../examples/borrow.reid"); | ||||||
| pub static ARITHMETIC: &str = include_str!("../../reid_src/arithmetic.reid"); | pub static ARITHMETIC: &str = include_str!("../../examples/arithmetic.reid"); | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn array_compiles_well() { | fn array_compiles_well() { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user