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 number = 100 * 5; | ||||||
| let text = "" + number; | let text = "" + number / 2; | ||||||
| print(text); | print(text); | ||||||
| @ -16,6 +16,8 @@ pub enum ArithmeticOp { | |||||||
|     Add(VariableType, VariableType, VariableType), |     Add(VariableType, VariableType, VariableType), | ||||||
|     Subtract(VariableType, VariableType, VariableType), |     Subtract(VariableType, VariableType, VariableType), | ||||||
|     Mult(VariableType, VariableType, VariableType), |     Mult(VariableType, VariableType, VariableType), | ||||||
|  |     Pow(VariableType, VariableType, VariableType), | ||||||
|  |     Div(VariableType, VariableType, VariableType), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct Compiler { | pub struct Compiler { | ||||||
| @ -31,6 +33,8 @@ impl Compiler { | |||||||
|             ArithmeticOp::Add(TypeI32, TypeI32, TypeI32), |             ArithmeticOp::Add(TypeI32, TypeI32, TypeI32), | ||||||
|             ArithmeticOp::Subtract(TypeI32, TypeI32, TypeI32), |             ArithmeticOp::Subtract(TypeI32, TypeI32, TypeI32), | ||||||
|             ArithmeticOp::Mult(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, TypeI32, TypeString), | ||||||
|             ArithmeticOp::Add(TypeString, TypeString, TypeString), |             ArithmeticOp::Add(TypeString, TypeString, TypeString), | ||||||
|         ]; |         ]; | ||||||
| @ -125,6 +129,8 @@ impl Compiler { | |||||||
|             ArithmeticExpression::Add(e1, e2) => (e1, e2), |             ArithmeticExpression::Add(e1, e2) => (e1, e2), | ||||||
|             ArithmeticExpression::Subtract(e1, e2) => (e1, e2), |             ArithmeticExpression::Subtract(e1, e2) => (e1, e2), | ||||||
|             ArithmeticExpression::Mult(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 type1 = self.handle_expression(exp1)?; | ||||||
|         let type2 = self.handle_expression(exp2)?; |         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 { |             let (command, error) = match exp { | ||||||
| @ -167,7 +189,13 @@ impl Compiler { | |||||||
|                     ArithmeticOp::Subtract(type1, type2, TypeI32), |                     ArithmeticOp::Subtract(type1, type2, TypeI32), | ||||||
|                 ), |                 ), | ||||||
|                 ArithmeticExpression::Mult(..) => { |                 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 { |             if let Some(t) = return_type { | ||||||
|  | |||||||
| @ -159,6 +159,12 @@ impl Display for CompilerError { | |||||||
|                     ArithmeticOp::Mult(t1, t2, _) => { |                     ArithmeticOp::Mult(t1, t2, _) => { | ||||||
|                         format!("{} * {}", t1.to_string(), t2.to_string()) |                         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) |                 format!("Invalid arithmetic operation: {}", text) | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -83,6 +83,8 @@ impl Command { | |||||||
|             Command::Add => 10, |             Command::Add => 10, | ||||||
|             Command::Subtract => 11, |             Command::Subtract => 11, | ||||||
|             Command::Mult => 12, |             Command::Mult => 12, | ||||||
|  |             Command::Pow => 13, | ||||||
|  |             Command::Div => 14, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -134,6 +136,8 @@ impl Command { | |||||||
|             10 => Some(Command::Add), |             10 => Some(Command::Add), | ||||||
|             11 => Some(Command::Subtract), |             11 => Some(Command::Subtract), | ||||||
|             12 => Some(Command::Mult), |             12 => Some(Command::Mult), | ||||||
|  |             13 => Some(Command::Pow), | ||||||
|  |             14 => Some(Command::Div), | ||||||
|             _ => None, |             _ => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -176,6 +180,8 @@ impl Command { | |||||||
|             Command::Add => (), |             Command::Add => (), | ||||||
|             Command::Subtract => (), |             Command::Subtract => (), | ||||||
|             Command::Mult => (), |             Command::Mult => (), | ||||||
|  |             Command::Pow => (), | ||||||
|  |             Command::Div => (), | ||||||
|         } |         } | ||||||
|         list |         list | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -120,6 +120,8 @@ pub enum ArithmeticExpression { | |||||||
|     Add(Expression, Expression), |     Add(Expression, Expression), | ||||||
|     Subtract(Expression, Expression), |     Subtract(Expression, Expression), | ||||||
|     Mult(Expression, Expression), |     Mult(Expression, Expression), | ||||||
|  |     Div(Expression, Expression), | ||||||
|  |     Pow(Expression, Expression), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ArithmeticExpression { | impl ArithmeticExpression { | ||||||
| @ -134,6 +136,8 @@ impl ArithmeticExpression { | |||||||
|                 .expect_static("+") |                 .expect_static("+") | ||||||
|                 .get() |                 .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()) | ||||||
|                 .or_else(|| parser.expect_static("*").get()); |                 .or_else(|| parser.expect_static("*").get()); | ||||||
|             if sign.is_some() { |             if sign.is_some() { | ||||||
|                 list.push((exp, sign.clone())); |                 list.push((exp, sign.clone())); | ||||||
| @ -146,11 +150,33 @@ impl ArithmeticExpression { | |||||||
|             return Err(SyntaxError::Fatal); |             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 clone = list.clone(); | ||||||
|         let iter = clone.iter().enumerate().rev(); |         let iter = clone.iter().enumerate().rev(); | ||||||
|         for (idx, (exp, sign)) in iter { |         for (idx, (exp, sign)) in iter { | ||||||
|             if let Some(sign) = sign { |             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 sign == "*" { | ||||||
|                     if let Some((exp2, sign2)) = list.clone().get(idx + 1) { |                     if let Some((exp2, sign2)) = list.clone().get(idx + 1) { | ||||||
|                         list.remove(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); |         let mut ret = Err(SyntaxError::Fatal); | ||||||
|         while list.len() > 1 { |         while list.len() > 1 { | ||||||
|             let (exp2, sign2) = list.remove(1); |             let (exp2, sign2) = list.remove(1); | ||||||
|  | |||||||
| @ -19,7 +19,9 @@ pub enum Command { | |||||||
|     FunctionCall(FuncID),                     // Call Function at FuncID
 |     FunctionCall(FuncID),                     // Call Function at FuncID
 | ||||||
|     Add,                                      // Add last two items on stack
 |     Add,                                      // Add last two items on stack
 | ||||||
|     Subtract,                                 // Subtract 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)] | #[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)] | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||||||
|  | |||||||
| @ -183,6 +183,28 @@ impl VirtualMachine { | |||||||
|                     Err(RuntimePanic::AttemptedInvalidArithmeticOperation) |                     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