start working on a bytecode interpreter!
This commit is contained in:
parent
d4af160f80
commit
86aea78c21
|
@ -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"
|
||||
|
|
47
src/byte_values.rs
Normal file
47
src/byte_values.rs
Normal file
|
@ -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<Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LFn {
|
||||
pub name: &'static str,
|
||||
pub body: Vec<Spanned<Ast>>,
|
||||
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<String>),
|
||||
Number(f64),
|
||||
List(Box<Vector<Value>>),
|
||||
Dict(Box<HashMap<&'static str, Value>>),
|
||||
Box(Rc<LBox>),
|
||||
Fn(Rc<RefCell<LFn>>),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
fn show(&self, ctx: &Chunk) -> String {
|
||||
use Value::*;
|
||||
match &self {
|
||||
Nil => format!("nil"),
|
||||
}
|
||||
}
|
||||
}
|
96
src/compiler.rs
Normal file
96
src/compiler.rs
Normal file
|
@ -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<Value<'a>>,
|
||||
pub bytecode: Vec<u8>,
|
||||
pub spans: Vec<SimpleSpan>,
|
||||
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<Ast>) {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
58
src/memory_sandbox.rs
Normal file
58
src/memory_sandbox.rs
Normal file
|
@ -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<Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct Fn {
|
||||
name: &'static str,
|
||||
body: Vec<String>,
|
||||
//...etc
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum Value {
|
||||
Nil,
|
||||
Placeholder,
|
||||
Boolean(bool),
|
||||
Keyword(usize),
|
||||
Interned(usize),
|
||||
FnDecl(usize),
|
||||
String(Rc<String>),
|
||||
Number(f64),
|
||||
Tuple(Rc<Vec<Value>>),
|
||||
List(Box<Vector<Value>>),
|
||||
Dict(Box<HashMap<&'static str, Value>>),
|
||||
Box(Rc<LBox>),
|
||||
Fn(Rc<RefCell<Fn>>),
|
||||
}
|
||||
|
||||
fn futz() {
|
||||
let foo: &'static str = "foo";
|
||||
let baz: Vec<u8> = vec![];
|
||||
let bar: Range<usize> = 1..3;
|
||||
let quux: Vector<u8> = Vector::new();
|
||||
let fuzz = Rc::new(quux);
|
||||
let blah = Box::new(foo);
|
||||
let val = Value::Number(12.09);
|
||||
let foo: f64 = 12.0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user