make some progress: atoms and ifs

This commit is contained in:
Scott Richmond 2024-12-15 23:28:57 -05:00
parent eff2ed90d5
commit 35fc591c76
3 changed files with 155 additions and 29 deletions

View File

@ -6,14 +6,37 @@ use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
enum Op { pub enum Op {
Return, Return,
Constant, Constant,
Jump,
JumpIfFalse,
}
impl std::fmt::Display for Op {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Op::*;
match self {
Return => write!(f, "return"),
Constant => write!(f, "constant"),
Jump => write!(f, "jump"),
JumpIfFalse => write!(f, "jump_if_false"),
}
}
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Chunk<'a> { pub struct Local {
pub constants: Vec<Value<'a>>, name: &'static str,
depth: u8,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Chunk<'a> {
pub locals: Vec<Local>,
scope_depth: usize,
local_count: usize,
pub constants: Vec<Value>,
pub bytecode: Vec<u8>, pub bytecode: Vec<u8>,
pub spans: Vec<SimpleSpan>, pub spans: Vec<SimpleSpan>,
pub strings: Vec<&'static str>, pub strings: Vec<&'static str>,
@ -26,7 +49,34 @@ struct Chunk<'a> {
} }
impl<'a> Chunk<'a> { impl<'a> Chunk<'a> {
fn visit(&mut self, node: &'a Spanned<Ast>) { pub fn new(ast: &'a Spanned<Ast>, name: &'static str, src: &'static str) -> Chunk<'a> {
Chunk {
locals: vec![],
scope_depth: 0,
local_count: 0,
constants: vec![],
bytecode: vec![],
spans: vec![],
strings: vec![],
keywords: vec![
"nil", "bool", "number", "keyword", "string", "tuple", "list", "",
],
nodes: vec![],
ast: &ast.0,
span: ast.1,
src,
name,
}
}
pub fn kw_from(&self, kw: &str) -> Option<Value> {
self.keywords
.iter()
.position(|s| *s == kw)
.map(Value::Keyword)
}
pub fn visit(&mut self, node: &'a Spanned<Ast>) {
let root_node = self.ast; let root_node = self.ast;
let root_span = self.span; let root_span = self.span;
let (ast, span) = node; let (ast, span) = node;
@ -37,7 +87,7 @@ impl<'a> Chunk<'a> {
self.span = root_span; self.span = root_span;
} }
fn emit_constant(&mut self, val: Value<'a>) { fn emit_constant(&mut self, val: Value) {
let constant_index = self.constants.len(); let constant_index = self.constants.len();
if constant_index > u8::MAX as usize { if constant_index > u8::MAX as usize {
panic!( panic!(
@ -57,39 +107,78 @@ impl<'a> Chunk<'a> {
self.spans.push(self.span); self.spans.push(self.span);
} }
fn compile(&mut self) { pub fn compile(&mut self) {
use Ast::*;
match self.ast { match self.ast {
Ast::Nil => self.emit_constant(Value::Nil), Nil => self.emit_constant(Value::Nil),
Ast::Number(n) => self.emit_constant(Value::Number(*n)), Number(n) => self.emit_constant(Value::Number(*n)),
Ast::Boolean(b) => self.emit_constant(Value::Boolean(*b)), Boolean(b) => self.emit_constant(if *b { Value::True } else { Value::False }),
Ast::String(s) => { String(s) => {
let str_index = self.strings.len(); let str_index = self.strings.len();
self.strings.push(s); self.strings.push(s);
self.emit_constant(Value::InternedString(s)); self.emit_constant(Value::Interned(str_index));
} }
Ast::Block(lines) => { Keyword(s) => {
let existing_kw = self.keywords.iter().position(|kw| kw == s);
let kw_index = match existing_kw {
Some(index) => index,
None => self.keywords.len(),
};
self.keywords.push(s);
self.emit_constant(Value::Keyword(kw_index));
}
Block(lines) => {
self.scope_depth += 1;
for expr in lines { for expr in lines {
self.visit(expr); self.visit(expr);
} }
self.emit_op(Op::Return); self.emit_op(Op::Return);
self.scope_depth -= 1;
} }
If(cond, then, r#else) => {
self.visit(cond);
let jif_idx = self.bytecode.len();
self.emit_op(Op::JumpIfFalse);
self.bytecode.push(0xff);
self.visit(then);
let jump_idx = self.bytecode.len();
self.emit_op(Op::Jump);
self.bytecode.push(0xff);
self.visit(r#else);
let end_idx = self.bytecode.len();
let jif_offset = jump_idx - jif_idx;
let jump_offset = end_idx - jump_idx;
self.bytecode[jif_idx + 1] = jif_offset as u8;
self.bytecode[jump_idx + 1] = jump_offset as u8;
}
// Let(patt, expr) => {
// self.visit(expr);
// self.visit(patt);
// }
// WordPattern(name) => {}
// PlaceholderPattern => {}
_ => todo!(), _ => todo!(),
} }
} }
fn disassemble(&self) { pub fn disassemble(&self) {
println!("=== chunk: {} ===", self.name); println!("=== chunk: {} ===", self.name);
println!("IDX | CODE | INFO");
let mut codes = self.bytecode.iter().enumerate(); let mut codes = self.bytecode.iter().enumerate();
while let Some((i, byte)) = codes.next() { while let Some((i, byte)) = codes.next() {
let op = Op::from_u8(*byte); let op = Op::from_u8(*byte).unwrap();
use Op::*;
match op { match op {
Some(Op::Return) => println!("{i:04}: {byte:16}"), Return => println!("{i:04}: {op}"),
Some(Op::Constant) => { Constant => {
let (_, next) = codes.next().unwrap(); let (_, next) = codes.next().unwrap();
let value = &self.constants[*next as usize]; let value = &self.constants[*next as usize].show(self);
println!("i:04: {byte:16} {next:16} {value}") println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
}
Jump | JumpIfFalse => {
let (_, next) = codes.next().unwrap();
println!("{i:04}: {:16} {next:04}", op.to_string())
} }
_ => unreachable!(),
} }
} }
} }

View File

@ -53,9 +53,9 @@ fn match_arities(arities: &HashSet<Arity>, num_args: u8) -> bool {
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Validator<'a, 'src> { pub struct Validator<'a> {
pub locals: Vec<(String, Span, FnInfo)>, pub locals: Vec<(String, Span, FnInfo)>,
pub prelude: &'a Vec<(String, Value<'src>)>, pub prelude: &'a Vec<(&'static str, Value)>,
pub input: &'static str, pub input: &'static str,
pub src: &'static str, pub src: &'static str,
pub ast: &'a Ast, pub ast: &'a Ast,
@ -65,14 +65,14 @@ pub struct Validator<'a, 'src> {
status: VStatus, status: VStatus,
} }
impl<'a, 'src: 'a> Validator<'a, 'src> { impl<'a> Validator<'a> {
pub fn new( pub fn new(
ast: &'a Ast, ast: &'a Ast,
span: Span, span: Span,
input: &'static str, input: &'static str,
src: &'static str, src: &'static str,
prelude: &'a Vec<(String, Value<'src>)>, prelude: &'a Vec<(&'static str, Value)>,
) -> Validator<'a, 'src> { ) -> Validator<'a> {
Validator { Validator {
input, input,
src, src,
@ -109,7 +109,7 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
fn resolved(&self, name: &str) -> bool { fn resolved(&self, name: &str) -> bool {
self.locals.iter().any(|(bound, ..)| name == bound.as_str()) self.locals.iter().any(|(bound, ..)| name == bound.as_str())
|| self.prelude.iter().any(|(bound, _)| name == bound.as_str()) || self.prelude.iter().any(|(bound, _)| name == *bound)
} }
fn bound(&self, name: &str) -> Option<&(String, Span, FnInfo)> { fn bound(&self, name: &str) -> Option<&(String, Span, FnInfo)> {

View File

@ -25,23 +25,60 @@ pub struct LFn {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Value { pub enum Value {
Nil, Nil,
Boolean(bool), True,
False,
Keyword(usize), // use an idx, rather than a raw index Keyword(usize), // use an idx, rather than a raw index
Interned(usize), Interned(usize),
FnDecl(usize), FnDecl(usize),
String(Rc<String>), String(Rc<String>),
Number(f64), Number(f64),
Tuple(Rc<Vec<Value>>),
TupleStart { len: u8, size: u16 },
TupleEnd { len: u8, size: u16 },
List(Box<Vector<Value>>), List(Box<Vector<Value>>),
Dict(Box<HashMap<&'static str, Value>>), Dict(Box<HashMap<usize, Value>>),
Box(Rc<LBox>), Box(Rc<LBox>),
Fn(Rc<RefCell<LFn>>), Fn(Rc<RefCell<LFn>>),
} }
impl Value { impl Value {
fn show(&self, ctx: &Chunk) -> String { pub fn show(&self, ctx: &Chunk) -> String {
use Value::*; use Value::*;
match &self { match &self {
Nil => format!("nil"), Nil => "nil".to_string(),
True => "true".to_string(),
False => "false".to_string(),
Number(n) => format!("{n}"),
Interned(i) => {
let str_str = ctx.strings[*i];
format!("\"{str_str}\"")
}
Keyword(i) => {
let kw_str = ctx.keywords[*i];
format!(":{kw_str}")
}
Tuple(t) => {
let members = t.iter().map(|e| e.show(ctx)).collect::<Vec<_>>().join(", ");
format!("({members})")
}
List(l) => {
let members = l.iter().map(|e| e.show(ctx)).collect::<Vec<_>>().join(", ");
format!("[{members}]")
}
Dict(d) => {
let members = d
.iter()
.map(|(k, v)| {
let key_show = Value::Keyword(*k).show(ctx);
let value_show = v.show(ctx);
format!("{key_show} {value_show}")
})
.collect::<Vec<_>>()
.join(", ");
format!("#{{{members}}}")
}
String(s) => s.as_ref().clone(),
_ => todo!(),
} }
} }
} }