keep working on vm

This commit is contained in:
Scott Richmond 2024-11-06 17:37:57 -05:00
parent f2b342a807
commit 740b14f9da
3 changed files with 39 additions and 37 deletions

View File

@ -59,12 +59,9 @@ pub fn main() {
.unwrap(); .unwrap();
println!("{}", ast); println!("{}", ast);
let mut ctx = Ctx { let mut ctx = vec![("foo", Value::Number(42.0))];
local_names: vec!["foo"],
local_values: vec![Value::Keyword("foo")],
};
let result = eval(ast, &mut ctx).unwrap(); let result = eval(&ast, &mut ctx).unwrap();
println!("{}", result); println!("{}", result);
} }

View File

@ -19,18 +19,18 @@ pub struct Fn<'src> {
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Value { pub enum Value<'src> {
Nil, Nil,
Boolean(bool), Boolean(bool),
Number(f64), Number(f64),
Keyword(&'static str), Keyword(&'src str),
String(&'static str), String(&'src str),
// on the heap for now // on the heap for now
Tuple(Rc<Vec<Self>>), Tuple(Rc<Vec<Self>>),
// ref-counted, immutable, persistent // ref-counted, immutable, persistent
List(Rc<Vector<Self>>), List(Rc<Vector<Self>>),
// ref-counted, immutable, persistent // ref-counted, immutable, persistent
Dict(Rc<HashMap<&'static str, Self>>), Dict(Rc<HashMap<&'src str, Self>>),
// Fn(Rc<Fn<'src>>), // Fn(Rc<Fn<'src>>),
// Set(HashSet<Self>), // Set(HashSet<Self>),
// Sets are hard // Sets are hard
@ -44,8 +44,8 @@ pub enum Value {
// pkgs, nses, tests // pkgs, nses, tests
} }
impl<'src> Clone for Value { impl<'src> Clone for Value<'src> {
fn clone(&self) -> Value { fn clone(&self) -> Value<'src> {
match self { match self {
Value::Nil => Value::Nil, Value::Nil => Value::Nil,
Value::Boolean(b) => Value::Boolean(b.clone()), Value::Boolean(b) => Value::Boolean(b.clone()),
@ -59,7 +59,7 @@ impl<'src> Clone for Value {
} }
} }
impl<'src> fmt::Display for Value { impl<'src> fmt::Display for Value<'src> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Value::Nil => write!(f, "nil"), Value::Nil => write!(f, "nil"),
@ -89,7 +89,7 @@ impl<'src> fmt::Display for Value {
} }
} }
impl Value { impl<'src> Value<'src> {
pub fn bool(&self) -> bool { pub fn bool(&self) -> bool {
match self { match self {
Value::Nil | Value::Boolean(false) => false, Value::Nil | Value::Boolean(false) => false,

View File

@ -18,33 +18,31 @@ pub struct LudusError {
// the branches for Ast::Block and Ast::If // the branches for Ast::Block and Ast::If
// to work with a mutable borrow of ctx // to work with a mutable borrow of ctx
pub struct Ctx<'src> { pub struct Ctx<'src> {
locals: Vec<(&'src str, Value)>, pub locals: Vec<(&'src str, Value<'src>)>,
} }
impl Ctx { impl<'src> Ctx<'src> {
pub fn resolve(&self, name: &str) -> Value { pub fn resolve(&self, name: &'src str) -> Value {
let len = self.local_names.len(); if let Some((_, val)) = self.locals.iter().rev().find(|(bound, _)| *bound == name) {
let mut value = Value::Nil; val.clone()
for i in (0..len).rev() { } else {
if self.local_names[i] == name { unreachable!()
value = self.local_values[i].clone();
break;
}
}
value
}
pub fn store(&mut self, name: &'static str, value: Value) {
self.local_names.push(name);
self.local_values.push(value);
} }
} }
pub fn eval<'src>(ast: Ast<'src>, ctx: &mut Ctx) -> Result<Value, LudusError> { pub fn store(&mut self, name: &'src str, value: Value<'src>) {
self.locals.push((name, value));
}
}
pub fn eval<'src, 'a>(
ast: &Ast<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
match ast { match ast {
Ast::Nil => Ok(Value::Nil), Ast::Nil => Ok(Value::Nil),
Ast::Boolean(b) => Ok(Value::Boolean(b)), Ast::Boolean(b) => Ok(Value::Boolean(*b)),
Ast::Number(n) => Ok(Value::Number(n)), Ast::Number(n) => Ok(Value::Number(*n)),
Ast::Keyword(k) => Ok(Value::Keyword(k.clone())), Ast::Keyword(k) => Ok(Value::Keyword(k.clone())),
Ast::String(s) => Ok(Value::String(s.clone())), Ast::String(s) => Ok(Value::String(s.clone())),
Ast::Block(exprs) => { Ast::Block(exprs) => {
@ -55,30 +53,37 @@ pub fn eval<'src>(ast: Ast<'src>, ctx: &mut Ctx) -> Result<Value, LudusError> {
Ok(result) Ok(result)
} }
Ast::If(cond, if_true, if_false) => { Ast::If(cond, if_true, if_false) => {
let truthy = eval((*cond).0, ctx)?.bool(); let truthy = eval(&cond.0, ctx)?.bool();
if truthy { if truthy {
let (if_true, _) = *if_true; let (if_true, _) = *if_true;
eval(if_true, ctx) eval(&if_true, ctx)
} else { } else {
let (if_false, _) = *if_false; let (if_false, _) = **if_false;
eval(if_false, ctx) eval(&if_false, ctx)
} }
} }
Ast::List(members) => { Ast::List(members) => {
let mut vect = Vector::new(); let mut vect = Vector::new();
for member in members { for member in members {
vect.push_back(eval(member.0, ctx)?) vect.push_back(eval(&member.0, ctx)?)
} }
Ok(Value::List(Rc::new(vect))) Ok(Value::List(Rc::new(vect)))
} }
Ast::Tuple(members) => { Ast::Tuple(members) => {
let mut vect = Vec::new(); let mut vect = Vec::new();
for member in members { for member in members {
vect.push(eval(member.0, ctx)?); vect.push(eval(&member.0, ctx)?);
} }
Ok(Value::Tuple(Rc::new(vect))) Ok(Value::Tuple(Rc::new(vect)))
} }
Ast::Word(w) => Ok(ctx.resolve(w)), Ast::Word(w) => {
let val = if let Some((_, value)) = ctx.iter().rev().find(|(name, _)| w == name) {
value.clone()
} else {
unreachable!()
};
Ok(val)
}
_ => todo!(), _ => todo!(),
} }
} }