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();
println!("{}", ast);
let mut ctx = Ctx {
local_names: vec!["foo"],
local_values: vec![Value::Keyword("foo")],
};
let mut ctx = vec![("foo", Value::Number(42.0))];
let result = eval(ast, &mut ctx).unwrap();
let result = eval(&ast, &mut ctx).unwrap();
println!("{}", result);
}

View File

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

View File

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