From 86aea78c218fc38bed068814b25aaf3014279057 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Sun, 15 Dec 2024 16:37:51 -0500 Subject: [PATCH] start working on a bytecode interpreter! --- Cargo.toml | 5 +++ src/byte_values.rs | 47 +++++++++++++++++++++ src/compiler.rs | 96 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 4 ++ src/memory_sandbox.rs | 58 ++++++++++++++++++++++++++ 5 files changed, 210 insertions(+) create mode 100644 src/byte_values.rs create mode 100644 src/compiler.rs create mode 100644 src/memory_sandbox.rs diff --git a/Cargo.toml b/Cargo.toml index e76b3b8..ff13e36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,8 @@ imbl = "3.0.0" struct_scalpel = "0.1.1" ran = "2.0.1" rust-embed = "8.5.0" +boxing = "0.1.2" +ordered-float = "4.5.0" +index_vec = "0.1.4" +num-derive = "0.4.2" +num-traits = "0.2.19" diff --git a/src/byte_values.rs b/src/byte_values.rs new file mode 100644 index 0000000..077e646 --- /dev/null +++ b/src/byte_values.rs @@ -0,0 +1,47 @@ +use crate::compiler::Chunk; +use crate::parser::Ast; +use crate::spans::Spanned; +use imbl::{HashMap, Vector}; +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Clone, Debug, PartialEq)] +pub struct LBox { + pub name: usize, + pub cell: RefCell, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct LFn { + pub name: &'static str, + pub body: Vec>, + pub doc: Option<&'static str>, + pub enclosing: Vec<(usize, Value)>, + pub has_run: bool, + pub input: &'static str, + pub src: &'static str, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Value { + Nil, + Boolean(bool), + Keyword(usize), // use an idx, rather than a raw index + Interned(usize), + FnDecl(usize), + String(Rc), + Number(f64), + List(Box>), + Dict(Box>), + Box(Rc), + Fn(Rc>), +} + +impl Value { + fn show(&self, ctx: &Chunk) -> String { + use Value::*; + match &self { + Nil => format!("nil"), + } + } +} diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..e5cd28e --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,96 @@ +use crate::parser::Ast; +use crate::spans::Spanned; +use crate::value::*; +use chumsky::prelude::SimpleSpan; +use num_derive::{FromPrimitive, ToPrimitive}; +use num_traits::FromPrimitive; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)] +enum Op { + Return, + Constant, +} + +#[derive(Clone, Debug, PartialEq)] +struct Chunk<'a> { + pub constants: Vec>, + pub bytecode: Vec, + pub spans: Vec, + pub strings: Vec<&'static str>, + pub keywords: Vec<&'static str>, + pub nodes: Vec<&'a Ast>, + pub ast: &'a Ast, + pub span: SimpleSpan, + pub src: &'static str, + pub name: &'static str, +} + +impl<'a> Chunk<'a> { + fn visit(&mut self, node: &'a Spanned) { + let root_node = self.ast; + let root_span = self.span; + let (ast, span) = node; + self.ast = ast; + self.span = *span; + self.compile(); + self.ast = root_node; + self.span = root_span; + } + + fn emit_constant(&mut self, val: Value<'a>) { + let constant_index = self.constants.len(); + if constant_index > u8::MAX as usize { + panic!( + "internal Ludus compiler error: too many constants in chunk:{}:: {}", + self.span, self.ast + ) + } + self.constants.push(val); + self.bytecode.push(Op::Constant as u8); + self.spans.push(self.span); + self.bytecode.push(constant_index as u8); + self.spans.push(self.span); + } + + fn emit_op(&mut self, op: Op) { + self.bytecode.push(op as u8); + self.spans.push(self.span); + } + + fn compile(&mut self) { + match self.ast { + Ast::Nil => self.emit_constant(Value::Nil), + Ast::Number(n) => self.emit_constant(Value::Number(*n)), + Ast::Boolean(b) => self.emit_constant(Value::Boolean(*b)), + Ast::String(s) => { + let str_index = self.strings.len(); + self.strings.push(s); + self.emit_constant(Value::InternedString(s)); + } + Ast::Block(lines) => { + for expr in lines { + self.visit(expr); + } + self.emit_op(Op::Return); + } + _ => todo!(), + } + } + + fn disassemble(&self) { + println!("=== chunk: {} ===", self.name); + let mut codes = self.bytecode.iter().enumerate(); + while let Some((i, byte)) = codes.next() { + let op = Op::from_u8(*byte); + match op { + Some(Op::Return) => println!("{i:04}: {byte:16}"), + Some(Op::Constant) => { + let (_, next) = codes.next().unwrap(); + let value = &self.constants[*next as usize]; + println!("i:04: {byte:16} {next:16} {value}") + } + _ => unreachable!(), + } + } + } +} diff --git a/src/main.rs b/src/main.rs index b0e9413..15750cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,6 +62,10 @@ use crate::process::*; mod errors; use crate::errors::*; +mod byte_values; +mod compiler; +mod memory_sandbox; + #[derive(Embed)] #[folder = "assets/"] struct Asset; diff --git a/src/memory_sandbox.rs b/src/memory_sandbox.rs new file mode 100644 index 0000000..15e7563 --- /dev/null +++ b/src/memory_sandbox.rs @@ -0,0 +1,58 @@ +use imbl::{HashMap, Vector}; +use index_vec::Idx; +use std::cell::RefCell; +use std::ops::Range; +use std::rc::Rc; + +struct Word(&'static str); + +struct Keyword(&'static str); + +struct Interned(&'static str); + +enum StringPart { + Word(&'static str), + Data(&'static str), + Inline(&'static str), +} + +#[derive(Clone, Debug, PartialEq)] +struct LBox { + name: usize, + cell: RefCell, +} + +#[derive(Clone, Debug, PartialEq)] +struct Fn { + name: &'static str, + body: Vec, + //...etc +} + +#[derive(Clone, Debug, PartialEq)] +enum Value { + Nil, + Placeholder, + Boolean(bool), + Keyword(usize), + Interned(usize), + FnDecl(usize), + String(Rc), + Number(f64), + Tuple(Rc>), + List(Box>), + Dict(Box>), + Box(Rc), + Fn(Rc>), +} + +fn futz() { + let foo: &'static str = "foo"; + let baz: Vec = vec![]; + let bar: Range = 1..3; + let quux: Vector = Vector::new(); + let fuzz = Rc::new(quux); + let blah = Box::new(foo); + let val = Value::Number(12.09); + let foo: f64 = 12.0; +}