make some progress: atoms and ifs
This commit is contained in:
parent
eff2ed90d5
commit
35fc591c76
127
src/compiler.rs
127
src/compiler.rs
|
@ -6,14 +6,37 @@ use num_derive::{FromPrimitive, ToPrimitive};
|
|||
use num_traits::FromPrimitive;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
enum Op {
|
||||
pub enum Op {
|
||||
Return,
|
||||
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)]
|
||||
struct Chunk<'a> {
|
||||
pub constants: Vec<Value<'a>>,
|
||||
pub struct Local {
|
||||
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 spans: Vec<SimpleSpan>,
|
||||
pub strings: Vec<&'static str>,
|
||||
|
@ -26,7 +49,34 @@ struct 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_span = self.span;
|
||||
let (ast, span) = node;
|
||||
|
@ -37,7 +87,7 @@ impl<'a> Chunk<'a> {
|
|||
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();
|
||||
if constant_index > u8::MAX as usize {
|
||||
panic!(
|
||||
|
@ -57,39 +107,78 @@ impl<'a> Chunk<'a> {
|
|||
self.spans.push(self.span);
|
||||
}
|
||||
|
||||
fn compile(&mut self) {
|
||||
pub fn compile(&mut self) {
|
||||
use Ast::*;
|
||||
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) => {
|
||||
Nil => self.emit_constant(Value::Nil),
|
||||
Number(n) => self.emit_constant(Value::Number(*n)),
|
||||
Boolean(b) => self.emit_constant(if *b { Value::True } else { Value::False }),
|
||||
String(s) => {
|
||||
let str_index = self.strings.len();
|
||||
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 {
|
||||
self.visit(expr);
|
||||
}
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn disassemble(&self) {
|
||||
pub fn disassemble(&self) {
|
||||
println!("=== chunk: {} ===", self.name);
|
||||
println!("IDX | CODE | INFO");
|
||||
let mut codes = self.bytecode.iter().enumerate();
|
||||
while let Some((i, byte)) = codes.next() {
|
||||
let op = Op::from_u8(*byte);
|
||||
let op = Op::from_u8(*byte).unwrap();
|
||||
use Op::*;
|
||||
match op {
|
||||
Some(Op::Return) => println!("{i:04}: {byte:16}"),
|
||||
Some(Op::Constant) => {
|
||||
Return => println!("{i:04}: {op}"),
|
||||
Constant => {
|
||||
let (_, next) = codes.next().unwrap();
|
||||
let value = &self.constants[*next as usize];
|
||||
println!("i:04: {byte:16} {next:16} {value}")
|
||||
let value = &self.constants[*next as usize].show(self);
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@ fn match_arities(arities: &HashSet<Arity>, num_args: u8) -> bool {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Validator<'a, 'src> {
|
||||
pub struct Validator<'a> {
|
||||
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 src: &'static str,
|
||||
pub ast: &'a Ast,
|
||||
|
@ -65,14 +65,14 @@ pub struct Validator<'a, 'src> {
|
|||
status: VStatus,
|
||||
}
|
||||
|
||||
impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||
impl<'a> Validator<'a> {
|
||||
pub fn new(
|
||||
ast: &'a Ast,
|
||||
span: Span,
|
||||
input: &'static str,
|
||||
src: &'static str,
|
||||
prelude: &'a Vec<(String, Value<'src>)>,
|
||||
) -> Validator<'a, 'src> {
|
||||
prelude: &'a Vec<(&'static str, Value)>,
|
||||
) -> Validator<'a> {
|
||||
Validator {
|
||||
input,
|
||||
src,
|
||||
|
@ -109,7 +109,7 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
|||
|
||||
fn resolved(&self, name: &str) -> bool {
|
||||
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)> {
|
||||
|
|
45
src/value.rs
45
src/value.rs
|
@ -25,23 +25,60 @@ pub struct LFn {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Value {
|
||||
Nil,
|
||||
Boolean(bool),
|
||||
True,
|
||||
False,
|
||||
Keyword(usize), // use an idx, rather than a raw index
|
||||
Interned(usize),
|
||||
FnDecl(usize),
|
||||
String(Rc<String>),
|
||||
Number(f64),
|
||||
Tuple(Rc<Vec<Value>>),
|
||||
TupleStart { len: u8, size: u16 },
|
||||
TupleEnd { len: u8, size: u16 },
|
||||
List(Box<Vector<Value>>),
|
||||
Dict(Box<HashMap<&'static str, Value>>),
|
||||
Dict(Box<HashMap<usize, Value>>),
|
||||
Box(Rc<LBox>),
|
||||
Fn(Rc<RefCell<LFn>>),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
fn show(&self, ctx: &Chunk) -> String {
|
||||
pub fn show(&self, ctx: &Chunk) -> String {
|
||||
use Value::*;
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user