Add pow and div arithmetic operators
This commit is contained in:
		
							parent
							
								
									529008a1fc
								
							
						
					
					
						commit
						6b87b51202
					
				| @ -1,3 +1,3 @@ | ||||
| let number = 2 * 5 * 2 - 10 + 5 * 7; | ||||
| let text = "" + number; | ||||
| let number = 100 * 5; | ||||
| let text = "" + number / 2; | ||||
| print(text); | ||||
| @ -16,6 +16,8 @@ pub enum ArithmeticOp { | ||||
|     Add(VariableType, VariableType, VariableType), | ||||
|     Subtract(VariableType, VariableType, VariableType), | ||||
|     Mult(VariableType, VariableType, VariableType), | ||||
|     Pow(VariableType, VariableType, VariableType), | ||||
|     Div(VariableType, VariableType, VariableType), | ||||
| } | ||||
| 
 | ||||
| pub struct Compiler { | ||||
| @ -31,6 +33,8 @@ impl Compiler { | ||||
|             ArithmeticOp::Add(TypeI32, TypeI32, TypeI32), | ||||
|             ArithmeticOp::Subtract(TypeI32, TypeI32, TypeI32), | ||||
|             ArithmeticOp::Mult(TypeI32, TypeI32, TypeI32), | ||||
|             ArithmeticOp::Pow(TypeI32, TypeI32, TypeI32), | ||||
|             ArithmeticOp::Div(TypeI32, TypeI32, TypeI32), | ||||
|             ArithmeticOp::Add(TypeString, TypeI32, TypeString), | ||||
|             ArithmeticOp::Add(TypeString, TypeString, TypeString), | ||||
|         ]; | ||||
| @ -125,6 +129,8 @@ impl Compiler { | ||||
|             ArithmeticExpression::Add(e1, e2) => (e1, e2), | ||||
|             ArithmeticExpression::Subtract(e1, e2) => (e1, e2), | ||||
|             ArithmeticExpression::Mult(e1, e2) => (e1, e2), | ||||
|             ArithmeticExpression::Pow(e1, e2) => (e1, e2), | ||||
|             ArithmeticExpression::Div(e1, e2) => (e1, e2), | ||||
|         }; | ||||
|         let type1 = self.handle_expression(exp1)?; | ||||
|         let type2 = self.handle_expression(exp2)?; | ||||
| @ -156,6 +162,22 @@ impl Compiler { | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     ArithmeticOp::Div(t1, t2, t3) => { | ||||
|                         if let ArithmeticExpression::Div(..) = exp { | ||||
|                             if (t1 == &type1 && t2 == &type2) || (t2 == &type1 && t1 == &type2) { | ||||
|                                 return_type = Some(t3); | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     ArithmeticOp::Pow(t1, t2, t3) => { | ||||
|                         if let ArithmeticExpression::Pow(..) = exp { | ||||
|                             if (t1 == &type1 && t2 == &type2) || (t2 == &type1 && t1 == &type2) { | ||||
|                                 return_type = Some(t3); | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             let (command, error) = match exp { | ||||
| @ -167,7 +189,13 @@ impl Compiler { | ||||
|                     ArithmeticOp::Subtract(type1, type2, TypeI32), | ||||
|                 ), | ||||
|                 ArithmeticExpression::Mult(..) => { | ||||
|                     (Command::Mult, ArithmeticOp::Subtract(type1, type2, TypeI32)) | ||||
|                     (Command::Mult, ArithmeticOp::Mult(type1, type2, TypeI32)) | ||||
|                 } | ||||
|                 ArithmeticExpression::Pow(..) => { | ||||
|                     (Command::Pow, ArithmeticOp::Pow(type1, type2, TypeI32)) | ||||
|                 } | ||||
|                 ArithmeticExpression::Div(..) => { | ||||
|                     (Command::Div, ArithmeticOp::Div(type1, type2, TypeI32)) | ||||
|                 } | ||||
|             }; | ||||
|             if let Some(t) = return_type { | ||||
|  | ||||
| @ -159,6 +159,12 @@ impl Display for CompilerError { | ||||
|                     ArithmeticOp::Mult(t1, t2, _) => { | ||||
|                         format!("{} * {}", t1.to_string(), t2.to_string()) | ||||
|                     } | ||||
|                     ArithmeticOp::Pow(t1, t2, _) => { | ||||
|                         format!("{} ** {}", t1.to_string(), t2.to_string()) | ||||
|                     } | ||||
|                     ArithmeticOp::Div(t1, t2, _) => { | ||||
|                         format!("{} / {}", t1.to_string(), t2.to_string()) | ||||
|                     } | ||||
|                 }; | ||||
|                 format!("Invalid arithmetic operation: {}", text) | ||||
|             } | ||||
|  | ||||
| @ -83,6 +83,8 @@ impl Command { | ||||
|             Command::Add => 10, | ||||
|             Command::Subtract => 11, | ||||
|             Command::Mult => 12, | ||||
|             Command::Pow => 13, | ||||
|             Command::Div => 14, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -134,6 +136,8 @@ impl Command { | ||||
|             10 => Some(Command::Add), | ||||
|             11 => Some(Command::Subtract), | ||||
|             12 => Some(Command::Mult), | ||||
|             13 => Some(Command::Pow), | ||||
|             14 => Some(Command::Div), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| @ -176,6 +180,8 @@ impl Command { | ||||
|             Command::Add => (), | ||||
|             Command::Subtract => (), | ||||
|             Command::Mult => (), | ||||
|             Command::Pow => (), | ||||
|             Command::Div => (), | ||||
|         } | ||||
|         list | ||||
|     } | ||||
|  | ||||
| @ -120,6 +120,8 @@ pub enum ArithmeticExpression { | ||||
|     Add(Expression, Expression), | ||||
|     Subtract(Expression, Expression), | ||||
|     Mult(Expression, Expression), | ||||
|     Div(Expression, Expression), | ||||
|     Pow(Expression, Expression), | ||||
| } | ||||
| 
 | ||||
| impl ArithmeticExpression { | ||||
| @ -134,6 +136,8 @@ impl ArithmeticExpression { | ||||
|                 .expect_static("+") | ||||
|                 .get() | ||||
|                 .or_else(|| parser.expect_static("-").get()) | ||||
|                 .or_else(|| parser.expect_static("**").get()) | ||||
|                 .or_else(|| parser.expect_static("/").get()) | ||||
|                 .or_else(|| parser.expect_static("*").get()); | ||||
|             if sign.is_some() { | ||||
|                 list.push((exp, sign.clone())); | ||||
| @ -146,11 +150,33 @@ impl ArithmeticExpression { | ||||
|             return Err(SyntaxError::Fatal); | ||||
|         } | ||||
| 
 | ||||
|         // Replace all (expr, "*"), (expr, any) => ((mult_expr, any)
 | ||||
|         // Replace all (expr, "*/**//"), (expr, any) => ((mult/pow/div_expr, any)
 | ||||
|         let clone = list.clone(); | ||||
|         let iter = clone.iter().enumerate().rev(); | ||||
|         for (idx, (exp, sign)) in iter { | ||||
|             if let Some(sign) = sign { | ||||
|                 if sign == "**" { | ||||
|                     if let Some((exp2, sign2)) = list.clone().get(idx + 1) { | ||||
|                         list.remove(idx + 1); | ||||
|                         list.remove(idx); | ||||
|                         let expr = Expression::ArithmeticExpression( | ||||
|                             parser.pos(), | ||||
|                             Box::new(ArithmeticExpression::Pow(exp.clone(), exp2.clone())), | ||||
|                         ); | ||||
|                         list.insert(idx, (expr, sign2.clone())); | ||||
|                     }; | ||||
|                 } | ||||
|                 if sign == "/" { | ||||
|                     if let Some((exp2, sign2)) = list.clone().get(idx + 1) { | ||||
|                         list.remove(idx + 1); | ||||
|                         list.remove(idx); | ||||
|                         let expr = Expression::ArithmeticExpression( | ||||
|                             parser.pos(), | ||||
|                             Box::new(ArithmeticExpression::Div(exp.clone(), exp2.clone())), | ||||
|                         ); | ||||
|                         list.insert(idx, (expr, sign2.clone())); | ||||
|                     }; | ||||
|                 } | ||||
|                 if sign == "*" { | ||||
|                     if let Some((exp2, sign2)) = list.clone().get(idx + 1) { | ||||
|                         list.remove(idx + 1); | ||||
| @ -165,6 +191,7 @@ impl ArithmeticExpression { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Replace all (expr, "+/-"), (expr, any) => ((add/sub_expr, any))
 | ||||
|         let mut ret = Err(SyntaxError::Fatal); | ||||
|         while list.len() > 1 { | ||||
|             let (exp2, sign2) = list.remove(1); | ||||
|  | ||||
| @ -19,7 +19,9 @@ pub enum Command { | ||||
|     FunctionCall(FuncID),                     // Call Function at FuncID
 | ||||
|     Add,                                      // Add last two items on stack
 | ||||
|     Subtract,                                 // Subtract last two items on stack
 | ||||
|     Mult,                                     // Subtract last two items on stack
 | ||||
|     Mult,                                     // Multiply last two items on stack
 | ||||
|     Pow,                                      // Take the power of last two items on stack
 | ||||
|     Div,                                      // Divide last two items on stack
 | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| @ -73,6 +75,26 @@ impl Value { | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn pow(self, other: Value) -> Option<Value> { | ||||
|         match self { | ||||
|             Value::StringVal(_) => None, | ||||
|             Value::I32Val(val) => match other { | ||||
|                 Value::I32Val(val2) => Some(Value::I32Val(val.pow(val2 as u32))), | ||||
|                 _ => None, | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn div(self, other: Value) -> Option<Value> { | ||||
|         match self { | ||||
|             Value::StringVal(_) => None, | ||||
|             Value::I32Val(val) => match other { | ||||
|                 Value::I32Val(val2) => Some(Value::I32Val(val / val2)), | ||||
|                 _ => None, | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||||
|  | ||||
| @ -183,6 +183,28 @@ impl VirtualMachine { | ||||
|                     Err(RuntimePanic::AttemptedInvalidArithmeticOperation) | ||||
|                 } | ||||
|             } | ||||
|             Command::Pow => { | ||||
|                 let val1 = self.pop_stack()?; | ||||
|                 let val2 = self.pop_stack()?; | ||||
|                 let res = val2.pow(val1); | ||||
|                 if let Some(res) = res { | ||||
|                     self.push_stack(res)?; | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::AttemptedInvalidArithmeticOperation) | ||||
|                 } | ||||
|             } | ||||
|             Command::Div => { | ||||
|                 let val1 = self.pop_stack()?; | ||||
|                 let val2 = self.pop_stack()?; | ||||
|                 let res = val2.div(val1); | ||||
|                 if let Some(res) = res { | ||||
|                     self.push_stack(res)?; | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::AttemptedInvalidArithmeticOperation) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user