Add for loop
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
7182024342
commit
42e0056374
16 changed files with 775 additions and 44 deletions
121
src/eval/mod.rs
121
src/eval/mod.rs
|
|
@ -6,7 +6,9 @@ use thiserror::Error;
|
|||
use crate::Context;
|
||||
use crate::emit::Instruction;
|
||||
use crate::emit::VMInstructions;
|
||||
use crate::emit::VariableSlot;
|
||||
use crate::input::NomoInput;
|
||||
use crate::value::NomoValue;
|
||||
|
||||
#[derive(Debug, Error, Display)]
|
||||
pub enum EvaluationError {
|
||||
|
|
@ -21,10 +23,59 @@ pub enum EvaluationError {
|
|||
LabelNotFound,
|
||||
}
|
||||
|
||||
struct Scope {
|
||||
stack: Vec<HashMap<String, NomoValue>>,
|
||||
slots: HashMap<VariableSlot, NomoValue>,
|
||||
}
|
||||
impl Scope {
|
||||
fn insert_into_slot(&mut self, slot: VariableSlot, value: NomoValue) {
|
||||
self.slots.insert(slot, value);
|
||||
}
|
||||
|
||||
fn get(&self, slot: &VariableSlot) -> &NomoValue {
|
||||
self.slots.get(slot).expect("All slot loads must be valid")
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, slot: &VariableSlot) -> &mut NomoValue {
|
||||
self.slots
|
||||
.get_mut(slot)
|
||||
.expect("All slot loads must be valid")
|
||||
}
|
||||
|
||||
fn push_scope(&mut self) {
|
||||
self.stack.push(Default::default());
|
||||
}
|
||||
|
||||
fn pop_scope(&mut self) {
|
||||
self.stack.pop();
|
||||
}
|
||||
|
||||
fn insert_into_scope(&mut self, ident: &NomoInput, value: NomoValue) {
|
||||
self.stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.insert(ident.to_string(), value);
|
||||
}
|
||||
|
||||
fn get_scoped(&self, name: &NomoInput) -> Option<&NomoValue> {
|
||||
self.stack
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|scope| scope.get(name.as_str()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(
|
||||
clippy::unnecessary_to_owned,
|
||||
reason = "We cannot do the suggested way as the lifetimes would not match up"
|
||||
)]
|
||||
pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result<String, EvaluationError> {
|
||||
let mut output = String::new();
|
||||
|
||||
let mut scopes: HashMap<crate::emit::VariableSlot, serde_json::Value> = HashMap::new();
|
||||
let mut scopes = Scope {
|
||||
stack: vec![global_context.values().clone()],
|
||||
slots: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut ip = 0;
|
||||
loop {
|
||||
|
|
@ -38,21 +89,22 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result<String,
|
|||
Instruction::NoOp => (),
|
||||
Instruction::AppendContent { content } => output.push_str(content),
|
||||
Instruction::LoadFromContextToSlot { name, slot } => {
|
||||
let value = global_context
|
||||
.values
|
||||
.get(name.as_str())
|
||||
let value = scopes
|
||||
.get_scoped(name)
|
||||
.ok_or(EvaluationError::UnknownVariable(name.clone()))?;
|
||||
|
||||
scopes.insert(*slot, value.clone());
|
||||
scopes.insert_into_slot(*slot, value.clone());
|
||||
}
|
||||
Instruction::EmitFromSlot { slot } => {
|
||||
let value = scopes.get(slot).unwrap().as_str().unwrap();
|
||||
let value = scopes.get(slot).as_str().unwrap();
|
||||
output.push_str(value);
|
||||
}
|
||||
Instruction::PushScope { inherit_parent: _ } => todo!(),
|
||||
Instruction::PushScope { inherit_parent: _ } => {
|
||||
scopes.push_scope();
|
||||
}
|
||||
Instruction::Abort => return Err(EvaluationError::ExplicitAbort),
|
||||
Instruction::JumpIfNotTrue { emit_slot, jump } => {
|
||||
let dont_jump = scopes.get(emit_slot).unwrap().as_bool().unwrap();
|
||||
let dont_jump = scopes.get(emit_slot).as_bool().unwrap();
|
||||
if dont_jump {
|
||||
// We are done
|
||||
} else {
|
||||
|
|
@ -72,6 +124,59 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result<String,
|
|||
ip = *new_ip;
|
||||
continue;
|
||||
}
|
||||
Instruction::CreateIteratorFromSlotToSlot {
|
||||
iterator_slot,
|
||||
iterator_source_slot,
|
||||
} => {
|
||||
let value = scopes.get(iterator_source_slot).as_array().unwrap();
|
||||
scopes.insert_into_slot(
|
||||
*iterator_slot,
|
||||
NomoValue::Iterator {
|
||||
value: Box::new(value.to_vec().into_iter()),
|
||||
},
|
||||
);
|
||||
}
|
||||
Instruction::AdvanceIteratorOrJump {
|
||||
iterator_slot,
|
||||
value_slot,
|
||||
jump,
|
||||
} => {
|
||||
let iterator = scopes.get_mut(iterator_slot).as_iterator_mut().unwrap();
|
||||
|
||||
if let Some(value) = iterator.next() {
|
||||
scopes.insert_into_slot(*value_slot, value);
|
||||
} else {
|
||||
let Some(new_ip) = vm.labels.get(jump) else {
|
||||
return Err(EvaluationError::LabelNotFound);
|
||||
};
|
||||
|
||||
ip = *new_ip;
|
||||
}
|
||||
}
|
||||
Instruction::GetIteratorEmptyOrJump {
|
||||
iterator_slot,
|
||||
jump,
|
||||
} => {
|
||||
let iterator = scopes.get(iterator_slot).as_iterator().unwrap();
|
||||
let (min, _) = iterator.size_hint();
|
||||
|
||||
if min == 0 {
|
||||
let Some(new_ip) = vm.labels.get(jump) else {
|
||||
return Err(EvaluationError::LabelNotFound);
|
||||
};
|
||||
|
||||
ip = *new_ip;
|
||||
}
|
||||
}
|
||||
Instruction::PopScope => scopes.pop_scope(),
|
||||
Instruction::LoadFromSlotToContext {
|
||||
value_ident,
|
||||
value_slot,
|
||||
} => {
|
||||
let value = scopes.get(value_slot).clone();
|
||||
|
||||
scopes.insert_into_scope(value_ident, value);
|
||||
}
|
||||
}
|
||||
|
||||
ip += 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue