Add evaluating of simple maths
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
05c095ccfe
commit
d222573a3a
8 changed files with 543 additions and 4 deletions
|
|
@ -3,6 +3,7 @@ use std::collections::BTreeMap;
|
|||
use crate::ast::TemplateAstExpr;
|
||||
use crate::input::NomoInput;
|
||||
use crate::parser::TemplateToken;
|
||||
use crate::parser::TokenOperator;
|
||||
use crate::value::NomoValue;
|
||||
|
||||
pub struct EmitMachine {
|
||||
|
|
@ -95,6 +96,12 @@ pub enum Instruction {
|
|||
value: NomoValue,
|
||||
slot: VariableSlot,
|
||||
},
|
||||
MathOperate {
|
||||
op: TokenOperator,
|
||||
left_slot: VariableSlot,
|
||||
right_slot: VariableSlot,
|
||||
result_slot: VariableSlot,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -416,7 +423,7 @@ fn emit_ast_expr(
|
|||
}
|
||||
|
||||
fn emit_expr_load(
|
||||
_machine: &mut EmitMachine,
|
||||
machine: &mut EmitMachine,
|
||||
eval: &mut Vec<Instruction>,
|
||||
emit_slot: VariableSlot,
|
||||
expression: &TemplateAstExpr<'_>,
|
||||
|
|
@ -435,6 +442,19 @@ fn emit_expr_load(
|
|||
slot: emit_slot,
|
||||
});
|
||||
}
|
||||
TemplateAstExpr::Operation { op, lhs, rhs } => {
|
||||
let left_slot = machine.reserve_slot();
|
||||
emit_expr_load(machine, eval, left_slot, lhs);
|
||||
let right_slot = machine.reserve_slot();
|
||||
emit_expr_load(machine, eval, right_slot, rhs);
|
||||
|
||||
eval.push(Instruction::MathOperate {
|
||||
op: *op,
|
||||
left_slot,
|
||||
right_slot,
|
||||
result_slot: emit_slot,
|
||||
});
|
||||
}
|
||||
TemplateAstExpr::Invalid { .. } => eval.push(Instruction::Abort),
|
||||
TemplateAstExpr::StaticContent { .. } | TemplateAstExpr::Interpolation { .. } => {
|
||||
unreachable!("Invalid AST here")
|
||||
|
|
@ -446,7 +466,6 @@ fn emit_expr_load(
|
|||
TemplateAstExpr::ForChain { .. } => todo!(),
|
||||
TemplateAstExpr::For { .. } => todo!(),
|
||||
TemplateAstExpr::ForElse => todo!(),
|
||||
TemplateAstExpr::Operation { .. } => todo!(),
|
||||
|
||||
TemplateAstExpr::IfConditional { .. } => todo!(),
|
||||
TemplateAstExpr::ConditionalContent { .. } => todo!(),
|
||||
|
|
|
|||
|
|
@ -96,8 +96,9 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result<String,
|
|||
scopes.insert_into_slot(*slot, value.clone());
|
||||
}
|
||||
Instruction::EmitFromSlot { slot } => {
|
||||
let value = scopes.get(slot).as_str().unwrap();
|
||||
output.push_str(value);
|
||||
let value = scopes.get(slot).try_to_string().unwrap();
|
||||
|
||||
output.push_str(&value);
|
||||
}
|
||||
Instruction::PushScope { inherit_parent: _ } => {
|
||||
scopes.push_scope();
|
||||
|
|
@ -186,6 +187,26 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result<String,
|
|||
} => {
|
||||
scopes.insert_into_slot(*slot, value.clone());
|
||||
}
|
||||
Instruction::MathOperate {
|
||||
op,
|
||||
left_slot,
|
||||
right_slot,
|
||||
result_slot,
|
||||
} => {
|
||||
let left_value = scopes.get(left_slot);
|
||||
let right_value = scopes.get(right_slot);
|
||||
|
||||
let result = match op {
|
||||
crate::parser::TokenOperator::Plus => left_value.try_add(right_value),
|
||||
crate::parser::TokenOperator::Minus => left_value.try_sub(right_value),
|
||||
crate::parser::TokenOperator::Times => left_value.try_mul(right_value),
|
||||
crate::parser::TokenOperator::Divide => left_value.try_div(right_value),
|
||||
crate::parser::TokenOperator::And => left_value.try_and(right_value),
|
||||
crate::parser::TokenOperator::Or => left_value.try_or(right_value),
|
||||
};
|
||||
|
||||
scopes.insert_into_slot(*result_slot, result.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
ip += 1;
|
||||
|
|
|
|||
141
src/value.rs
141
src/value.rs
|
|
@ -97,6 +97,147 @@ impl NomoValue {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_add(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
match (self, right_value) {
|
||||
(NomoValue::Integer { value: lval }, NomoValue::Integer { value: rval }) => {
|
||||
Some(NomoValue::Integer {
|
||||
value: *lval + *rval,
|
||||
})
|
||||
}
|
||||
(
|
||||
NomoValue::SignedInteger { value: lval },
|
||||
NomoValue::SignedInteger { value: rval },
|
||||
) => Some(NomoValue::SignedInteger {
|
||||
value: *lval + *rval,
|
||||
}),
|
||||
(NomoValue::Integer { value: val }, NomoValue::SignedInteger { value: sval })
|
||||
| (NomoValue::SignedInteger { value: sval }, NomoValue::Integer { value: val }) => {
|
||||
Some(NomoValue::SignedInteger {
|
||||
value: (i64::try_from(*val).ok()?) + *sval,
|
||||
})
|
||||
}
|
||||
(NomoValue::String { value: rstr }, NomoValue::String { value: lstr }) => {
|
||||
Some(NomoValue::String {
|
||||
value: Cow::Owned(format!("{rstr}{lstr}")),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_sub(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
macro_rules! op {
|
||||
($left:expr, $right:expr) => {{ ($left) - ($right) }};
|
||||
}
|
||||
match (self, right_value) {
|
||||
(NomoValue::Integer { value: lval }, NomoValue::Integer { value: rval }) => {
|
||||
Some(NomoValue::Integer {
|
||||
value: op!(*lval, *rval),
|
||||
})
|
||||
}
|
||||
(
|
||||
NomoValue::SignedInteger { value: lval },
|
||||
NomoValue::SignedInteger { value: rval },
|
||||
) => Some(NomoValue::SignedInteger {
|
||||
value: op!(*lval, *rval),
|
||||
}),
|
||||
(NomoValue::Integer { value: val }, NomoValue::SignedInteger { value: sval })
|
||||
| (NomoValue::SignedInteger { value: sval }, NomoValue::Integer { value: val }) => {
|
||||
Some(NomoValue::SignedInteger {
|
||||
value: op!(i64::try_from(*val).ok()?, *sval),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_mul(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
macro_rules! op {
|
||||
($left:expr, $right:expr) => {{ ($left) * ($right) }};
|
||||
}
|
||||
match (self, right_value) {
|
||||
(NomoValue::Integer { value: lval }, NomoValue::Integer { value: rval }) => {
|
||||
Some(NomoValue::Integer {
|
||||
value: op!(*lval, *rval),
|
||||
})
|
||||
}
|
||||
(
|
||||
NomoValue::SignedInteger { value: lval },
|
||||
NomoValue::SignedInteger { value: rval },
|
||||
) => Some(NomoValue::SignedInteger {
|
||||
value: op!(*lval, *rval),
|
||||
}),
|
||||
(NomoValue::Integer { value: val }, NomoValue::SignedInteger { value: sval })
|
||||
| (NomoValue::SignedInteger { value: sval }, NomoValue::Integer { value: val }) => {
|
||||
Some(NomoValue::SignedInteger {
|
||||
value: op!(i64::try_from(*val).ok()?, *sval),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_div(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
macro_rules! op {
|
||||
($left:expr, $right:expr) => {{ ($left) / ($right) }};
|
||||
}
|
||||
match (self, right_value) {
|
||||
(NomoValue::Integer { value: lval }, NomoValue::Integer { value: rval }) => {
|
||||
Some(NomoValue::Integer {
|
||||
value: op!(*lval, *rval),
|
||||
})
|
||||
}
|
||||
(
|
||||
NomoValue::SignedInteger { value: lval },
|
||||
NomoValue::SignedInteger { value: rval },
|
||||
) => Some(NomoValue::SignedInteger {
|
||||
value: op!(*lval, *rval),
|
||||
}),
|
||||
(NomoValue::Integer { value: val }, NomoValue::SignedInteger { value: sval })
|
||||
| (NomoValue::SignedInteger { value: sval }, NomoValue::Integer { value: val }) => {
|
||||
Some(NomoValue::SignedInteger {
|
||||
value: op!(i64::try_from(*val).ok()?, *sval),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_and(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
match (self, right_value) {
|
||||
(NomoValue::Bool { value: lval }, NomoValue::Bool { value: rval }) => {
|
||||
Some(NomoValue::Bool {
|
||||
value: *lval && *rval,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_or(&self, right_value: &NomoValue) -> Option<NomoValue> {
|
||||
match (self, right_value) {
|
||||
(NomoValue::Bool { value: lval }, NomoValue::Bool { value: rval }) => {
|
||||
Some(NomoValue::Bool {
|
||||
value: *lval || *rval,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn try_to_string(&self) -> Option<String> {
|
||||
match self {
|
||||
NomoValue::String { value } => Some(value.to_string()),
|
||||
NomoValue::Array { .. } => None,
|
||||
NomoValue::Bool { value } => Some(value.to_string()),
|
||||
NomoValue::Object { .. } => None,
|
||||
NomoValue::Integer { value } => Some(value.to_string()),
|
||||
NomoValue::SignedInteger { value } => Some(value.to_string()),
|
||||
NomoValue::Float { value } => Some(value.to_string()),
|
||||
NomoValue::Iterator { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CloneIterator: Iterator<Item = NomoValue> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue