Add div/mod parsing
This commit is contained in:
		
							parent
							
								
									691c91504b
								
							
						
					
					
						commit
						b9459a19bb
					
				| @ -46,11 +46,16 @@ Currently missing big features (TODOs) are: | ||||
| - Loops | ||||
| - Debug Information (PARTIALLY DONE) | ||||
| - Ability to specify types in literals and variable definitions | ||||
| - Intrinsic functions | ||||
| - Not-Unary | ||||
| 
 | ||||
| Big features that I want later but are not necessary: | ||||
| - Associated functions | ||||
| - User-defined binary operations | ||||
| - Asymmetric binary operations (e.g. string + u32) | ||||
| - Error handling | ||||
| - Lexing & parsing of whitespace and comments as well | ||||
| - LSP implementation | ||||
| 
 | ||||
| Smaller features: | ||||
| - 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, | ||||
|     Minus, | ||||
|     Mult, | ||||
|     Div, | ||||
|     Mod, | ||||
| 
 | ||||
|     And, | ||||
|     LT, | ||||
| @ -95,9 +97,11 @@ impl BinaryOperator { | ||||
|     pub fn get_precedence(&self) -> i8 { | ||||
|         use BinaryOperator::*; | ||||
|         match &self { | ||||
|             Minus => 5, | ||||
|             Add => 10, | ||||
|             Minus => 10, | ||||
|             Mult => 20, | ||||
|             Mult => 15, | ||||
|             Div => 20, | ||||
|             Mod => 20, | ||||
|             And => 100, | ||||
|             LT => 100, | ||||
|             LE => 100, | ||||
|  | ||||
| @ -350,6 +350,8 @@ impl Parse for BinaryOperator { | ||||
|             (Some(Token::Plus), _) => BinaryOperator::Add, | ||||
|             (Some(Token::Minus), _) => BinaryOperator::Minus, | ||||
|             (Some(Token::Star), _) => BinaryOperator::Mult, | ||||
|             (Some(Token::Slash), _) => BinaryOperator::Div, | ||||
|             (Some(Token::Percent), _) => BinaryOperator::Mod, | ||||
|             (_, _) => Err(stream.expected_err("expected operator")?)?, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @ -286,6 +286,8 @@ impl ast::BinaryOperator { | ||||
|             ast::BinaryOperator::Minus => mir::BinaryOperator::Minus, | ||||
|             ast::BinaryOperator::Mult => mir::BinaryOperator::Mult, | ||||
|             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::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE), | ||||
|             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::Cmp(i), _, false) => Instr::ICmp(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( | ||||
|                     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']; | ||||
| 
 | ||||
| #[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)] | ||||
| #[derive(Eq, PartialEq, Clone, PartialOrd, Ord)] | ||||
| pub enum Token { | ||||
|     /// Values
 | ||||
|     Identifier(String), | ||||
| @ -56,6 +56,10 @@ pub enum Token { | ||||
|     Star, | ||||
|     /// `-`
 | ||||
|     Minus, | ||||
|     /// `/`
 | ||||
|     Slash, | ||||
|     /// `%`
 | ||||
|     Percent, | ||||
| 
 | ||||
|     /// `>`
 | ||||
|     GreaterThan, | ||||
| @ -83,6 +87,8 @@ pub enum Token { | ||||
|     /// `.`
 | ||||
|     Dot, | ||||
| 
 | ||||
|     Unknown(char), | ||||
| 
 | ||||
|     Eof, | ||||
| } | ||||
| 
 | ||||
| @ -149,6 +155,18 @@ impl ToString for Token { | ||||
|             Token::Comma => String::from(','), | ||||
|             Token::Dot => String::from('.'), | ||||
|             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 { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         f.write_fmt(format_args!( | ||||
|             "{:?} (Ln {}, Col {})", | ||||
|             "Token({:?}) (Ln {}, Col {})", | ||||
|             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::Comma, | ||||
|             '.' => Token::Dot, | ||||
|             // Invalid token
 | ||||
|             _ => Err(Error::InvalidToken(*character, cursor.position))?, | ||||
|             '/' => Token::Slash, | ||||
|             '%' => Token::Percent, | ||||
|             // Unknown token
 | ||||
|             value => Token::Unknown(*value), | ||||
|         }; | ||||
| 
 | ||||
|         tokens.push(FullToken { | ||||
|  | ||||
| @ -299,6 +299,8 @@ impl Display for BinaryOperator { | ||||
|             BinaryOperator::Mult => write!(f, "*"), | ||||
|             BinaryOperator::And => write!(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::And => 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> { | ||||
|         match op { | ||||
|             BinaryOperator::Add | BinaryOperator::Minus | BinaryOperator::Mult => { | ||||
|                 Some(self.clone()) | ||||
|             } | ||||
|             BinaryOperator::Add | ||||
|             | BinaryOperator::Minus | ||||
|             | BinaryOperator::Mult | ||||
|             | BinaryOperator::Div | ||||
|             | BinaryOperator::Mod => Some(self.clone()), | ||||
|             BinaryOperator::And => None, | ||||
|             BinaryOperator::Cmp(_) => None, | ||||
|         } | ||||
| @ -465,12 +471,16 @@ impl Expression { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_zero(&self) -> Option<bool> { | ||||
|         Some(self.num_value()? == 0) | ||||
|     pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> { | ||||
|         if let Some(val) = self.num_value()? { | ||||
|             Ok(Some(val == 0)) | ||||
|         } else { | ||||
|             Ok(None) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn num_value(&self) -> Option<i128> { | ||||
|         match &self.0 { | ||||
|     pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> { | ||||
|         Ok(match &self.0 { | ||||
|             ExprKind::Variable(_) => None, | ||||
|             ExprKind::Indexed(..) => None, | ||||
|             ExprKind::Accessed(..) => None, | ||||
| @ -478,22 +488,46 @@ impl Expression { | ||||
|             ExprKind::Struct(..) => None, | ||||
|             ExprKind::Literal(literal) => literal.num_value(), | ||||
|             ExprKind::BinOp(op, lhs, rhs) => match op { | ||||
|                 BinaryOperator::Add => Some(lhs.num_value()? + rhs.num_value()?), | ||||
|                 BinaryOperator::Minus => Some(lhs.num_value()? - rhs.num_value()?), | ||||
|                 BinaryOperator::Mult => Some(lhs.num_value()? * rhs.num_value()?), | ||||
|                 BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b), | ||||
|                 BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b), | ||||
|                 BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b), | ||||
|                 BinaryOperator::And => 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::If(_) => None, | ||||
|             ExprKind::Block(_) => None, | ||||
|             ExprKind::Borrow(_, _) => 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 { | ||||
|     pub fn return_type( | ||||
|         &self, | ||||
|  | ||||
| @ -218,6 +218,8 @@ pub enum BinaryOperator { | ||||
|     Add, | ||||
|     Minus, | ||||
|     Mult, | ||||
|     Div, | ||||
|     Mod, | ||||
|     And, | ||||
|     Cmp(CmpOperator), | ||||
| } | ||||
|  | ||||
| @ -68,6 +68,8 @@ pub enum ErrorKind { | ||||
|     NegativeUnsignedValue(TypeKind), | ||||
|     #[error("Cannot cast type {0} into type {1}!")] | ||||
|     NotCastableTo(TypeKind, TypeKind), | ||||
|     #[error("Cannot divide by zero")] | ||||
|     DivideZero, | ||||
| } | ||||
| 
 | ||||
| /// 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)?; | ||||
| 
 | ||||
|                 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 { | ||||
|                             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)] | ||||
| pub enum Error { | ||||
|     #[error("Expected {} got \"{}\"", .0, .1.to_string())] | ||||
|     #[error("Expected {} got \"{:?}\"", .0, .1)] | ||||
|     Expected(String, Token, TokenRange), | ||||
|     #[error("Source file contains no tokens")] | ||||
|     FileEmpty, | ||||
|  | ||||
| @ -18,15 +18,15 @@ fn test(source: &str, name: &str) { | ||||
|     )); | ||||
| } | ||||
| 
 | ||||
| pub static ARRAY: &str = include_str!("../../reid_src/array.reid"); | ||||
| pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid"); | ||||
| pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid"); | ||||
| pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid"); | ||||
| pub static STRINGS: &str = include_str!("../../reid_src/strings.reid"); | ||||
| pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid"); | ||||
| pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid"); | ||||
| pub static BORROW: &str = include_str!("../../reid_src/borrow.reid"); | ||||
| pub static ARITHMETIC: &str = include_str!("../../reid_src/arithmetic.reid"); | ||||
| pub static ARRAY: &str = include_str!("../../examples/array.reid"); | ||||
| pub static FIBONACCI: &str = include_str!("../../examples/fibonacci.reid"); | ||||
| pub static HELLO_WORLD: &str = include_str!("../../examples/hello_world.reid"); | ||||
| pub static MUTABLE: &str = include_str!("../../examples/mutable.reid"); | ||||
| pub static STRINGS: &str = include_str!("../../examples/strings.reid"); | ||||
| pub static STRUCTS: &str = include_str!("../../examples/struct.reid"); | ||||
| pub static ARRAY_STRUCTS: &str = include_str!("../../examples/array_structs.reid"); | ||||
| pub static BORROW: &str = include_str!("../../examples/borrow.reid"); | ||||
| pub static ARITHMETIC: &str = include_str!("../../examples/arithmetic.reid"); | ||||
| 
 | ||||
| #[test] | ||||
| fn array_compiles_well() { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user