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