関数を値として持っておくのだが変数と同じように、/で始まり、かつ{ } の場合、{ }の中身をoperationとして評価している
use std::{ collections::HashMap, io::{BufRead, BufReader}, }; #[derive(Debug, Clone, PartialEq, Eq)] enum Value { Num(i32), Op(String), Sym(String), Block(Vec<Value>), Native(NativeOp), } impl Value { fn as_num(&self) -> i32 { match self { Self::Num(val) => *val, _ => panic!("Value is not a number"), } } fn to_block(self) -> Vec<Value> { match self { Self::Block(val) => val, _ => panic!("Value is not a block"), } } fn as_sym(&self) -> &str { if let Self::Sym(sym) = self { sym } else { panic!("Value is not a symbol"); } } fn to_string(&self) -> String { match self { Self::Num(i) => i.to_string(), Self::Op(ref s) | Self::Sym(ref s) => s.clone(), Self::Block(_) => "<Block>".to_string(), Self::Native(_) => "<Native>".to_string(), } } } #[derive(Clone)] struct NativeOp(fn(&mut Vm)); impl PartialEq for NativeOp { fn eq(&self, other: &NativeOp) -> bool { self.0 as *const fn() == other.0 as *const fn() } } impl Eq for NativeOp {} impl std::fmt::Debug for NativeOp { fn fmt( &self, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { write!(f, "<NativeOp>") } } struct Vm { stack: Vec<Value>, vars: HashMap<String, Value>, blocks: Vec<Vec<Value>>, } impl Vm { fn new() -> Self { let functions: [(&str, fn(&mut Vm)); 12] = [ ("+", add), ("-", sub), ("*", mul), ("/", div), ("<", lt), ("if", op_if), ("def", op_def), ("puts", puts), ("pop", pop), ("dup", dup), ("exch", exch), ("index", index), ]; Self { stack: vec![], vars: functions .into_iter() .map(|(name, fun)| { (name.to_owned(), Value::Native(NativeOp(fun))) }) .collect(), blocks: vec![], } } } fn main() { if let Some(f) = std::env::args() .nth(1) .and_then(|f| std::fs::File::open(f).ok()) { parse_batch(BufReader::new(f)); } else { parse_interactive(); } } fn parse_batch(source: impl BufRead) -> Vec<Value> { let mut vm = Vm::new(); for line in source.lines().flatten() { for word in line.split(" ") { parse_word(word, &mut vm); } } vm.stack } fn parse_interactive() { let mut vm = Vm::new(); for line in std::io::stdin().lines().flatten() { for word in line.split(" ") { parse_word(word, &mut vm); } println!("stack: {:?}", vm.stack); } } fn parse_word(word: &str, vm: &mut Vm) { if word.is_empty() { return; } if word == "{" { vm.blocks.push(vec![]); } else if word == "}" { let top_block = vm.blocks.pop().expect("Block stack underflow!"); eval(Value::Block(top_block), vm); } else { let code = if let Ok(num) = word.parse::<i32>() { Value::Num(num) } else if word.starts_with("/") { Value::Sym(word[1..].to_string()) } else { Value::Op(word.to_string()) }; eval(code, vm); } } fn eval(code: Value, vm: &mut Vm) { if let Some(top_block) = vm.blocks.last_mut() { top_block.push(code); return; } if let Value::Op(ref op) = code { let val = vm .vars .get(op) .expect(&format!("{op:?} is not a defined operation")) .clone(); match val { Value::Block(block) => { for code in block { eval(code, vm); } } Value::Native(op) => op.0(vm), _ => vm.stack.push(val), } } else { vm.stack.push(code.clone()); } } macro_rules! impl_op { {$name:ident, $op:tt} => { fn $name(vm: &mut Vm) { let rhs = vm.stack.pop().unwrap().as_num(); let lhs = vm.stack.pop().unwrap().as_num(); vm.stack.push(Value::Num((lhs $op rhs) as i32)); } } } impl_op!(add, +); impl_op!(sub, -); impl_op!(mul, *); impl_op!(div, /); impl_op!(lt, <); fn op_if(vm: &mut Vm) { let false_branch = vm.stack.pop().unwrap().to_block(); let true_branch = vm.stack.pop().unwrap().to_block(); let cond = vm.stack.pop().unwrap().to_block(); for code in cond { eval(code, vm); } let cond_result = vm.stack.pop().unwrap().as_num(); if cond_result != 0 { for code in true_branch { eval(code, vm); } } else { for code in false_branch { eval(code, vm); } } } fn op_def(vm: &mut Vm) { let value = vm.stack.pop().unwrap(); eval(value, vm); let value = vm.stack.pop().unwrap(); let sym = vm.stack.pop().unwrap().as_sym().to_string(); vm.vars.insert(sym, value); } fn puts(vm: &mut Vm){ let value = vm.stack.pop().unwrap(); println!("{}", value.to_string()); } fn pop(vm: &mut Vm) { vm.stack.pop().unwrap(); } fn dup(vm: &mut Vm) { let value = vm.stack.last().unwrap(); vm.stack.push(value.clone()); } fn exch(vm: &mut Vm) { let last = vm.stack.pop().unwrap(); let second = vm.stack.pop().unwrap(); vm.stack.push(last); vm.stack.push(second); } fn index(vm: &mut Vm) { let index = vm.stack.pop().unwrap().as_num() as usize; let value = vm.stack[vm.stack.len() - index - 1].clone(); vm.stack.push(value); } #[cfg(test)] mod test { use super::{Value::*, *}; use std::io::Cursor; fn parse(input: &str) -> Vec<Value> { parse_batch(Cursor::new(input)) } #[test] fn test_group(){ assert_eq!( parse("1 2 + { 3 4 }"), vec![Num(3), Block(vec![Num(3), Num(4)])] ); } #[test] fn test_if_false(){ assert_eq!( parse("{ 1 -1 + } { 100 } { -100 } if"), vec![Num(-100)] ); } #[test] fn test_if_true() { assert_eq!( parse("{ 1 1 + } { 100 } { -100 } if"), vec![Num(100)] ); } #[test] fn test_var() { assert_eq!( parse("/x 10 def /y 20 def x y *"), vec![Num(200)] ) } #[test] fn test_var_if() { assert_eq!( parse("/x 10 def /y 20 def { x y < } { x } { y } if"), vec![Num(10)] ); } #[test] fn test_multiline() { assert_eq!( parse( r#" /x 10 def /y 20 def { x y < } { x } { y } if "# ), vec![Num(10)] ); } #[test] fn test_function() { assert_eq!( parse( r#" /double { 2 * } def 10 double"# ), vec![Num(20)] ); } }
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s
Running `target/debug/stackmachine`
/double { 2 * } def
stack: []
10 double puts
20
stack: []
ルールとしてわかりやすいように定義していくのね
考え方としては非常に参考になるものがあります