From 096d8d00bc9f7498c60a583630b0eab1c9ed41a0 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Sun, 15 Dec 2024 23:50:12 -0500 Subject: [PATCH] add untracked from opening bytecode branch --- src/main.rs | 68 +++++++++++++++++++++++++++++++++++++++++ src/vm.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/main.rs create mode 100644 src/vm.rs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f38488b --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +use chumsky::{input::Stream, prelude::*}; + +mod spans; + +mod lexer; +use crate::lexer::lexer; + +mod parser; +use crate::parser::parser; + +mod validator; + +mod compiler; +use crate::compiler::Chunk; + +mod value; + +mod vm; +use vm::Vm; + +pub fn run(src: &'static str) { + let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); + if !lex_errs.is_empty() { + println!("{:?}", lex_errs); + return; + } + + let tokens = tokens.unwrap(); + + let (parse_result, parse_errors) = parser() + .parse(Stream::from_iter(tokens).map((0..src.len()).into(), |(t, s)| (t, s))) + .into_output_errors(); + if !parse_errors.is_empty() { + println!("{:?}", parse_errors); + return; + } + + let parsed = parse_result.unwrap(); + + let mut chunk = Chunk::new(&parsed, "test", src); + chunk.compile(); + chunk.disassemble(); + + let mut vm = Vm::new(&chunk); + let result = vm.interpret(); + let output = match result { + Ok(val) => val.show(&chunk), + Err(panic) => format!("{:?}", panic), + }; + println!("{output}"); +} + +pub fn main() { + let src = " +if false + then { + :foo + :bar + :baz + } + else { + 1 + 2 + 3 + } + "; + run(src); +} diff --git a/src/vm.rs b/src/vm.rs new file mode 100644 index 0000000..33c4f6c --- /dev/null +++ b/src/vm.rs @@ -0,0 +1,87 @@ +use crate::compiler::{Chunk, Op}; +use crate::parser::Ast; +use crate::spans::Spanned; +use crate::value::Value; +use chumsky::prelude::SimpleSpan; +use num_traits::FromPrimitive; + +#[derive(Debug, Clone, PartialEq)] +pub struct Panic { + pub input: &'static str, + pub src: &'static str, + pub msg: String, + pub span: SimpleSpan, + pub trace: Vec, + pub extra: String, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Trace { + pub callee: Spanned, + pub caller: Spanned, + pub function: Value, + pub arguments: Value, + pub input: &'static str, + pub src: &'static str, +} + +pub struct Vm<'a> { + pub stack: Vec, + pub chunk: &'a Chunk<'a>, + pub ip: usize, + pub bindings: Vec<(u8, usize)>, +} + +impl<'a> Vm<'a> { + pub fn new(chunk: &'a Chunk) -> Vm<'a> { + Vm { + chunk, + stack: vec![], + ip: 0, + bindings: vec![], + } + } + + pub fn push(&mut self, value: Value) { + self.stack.push(value); + } + + pub fn pop(&mut self) -> Value { + self.stack.pop().unwrap() + } + + pub fn interpret(&mut self) -> Result { + let byte = self.chunk.bytecode[self.ip]; + let op = Op::from_u8(byte).unwrap(); + use Op::*; + match op { + Return => Ok(self.stack.pop().unwrap()), + Constant => { + let const_idx = self.chunk.bytecode[self.ip + 1]; + let value = self.chunk.constants[const_idx as usize].clone(); + self.push(value); + self.ip += 2; + self.interpret() + } + Jump => { + let jump_len = self.chunk.bytecode[self.ip + 1]; + self.ip += jump_len as usize; + self.interpret() + } + JumpIfFalse => { + let jump_len = self.chunk.bytecode[self.ip + 1]; + let cond = self.stack.pop().unwrap(); + match cond { + Value::Nil | Value::False => { + self.ip += jump_len as usize + 2; + self.interpret() + } + _ => { + self.ip += 2; + self.interpret() + } + } + } + } + } +}