keep working on vm
This commit is contained in:
parent
f2b342a807
commit
740b14f9da
|
@ -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);
|
||||
}
|
||||
|
|
16
src/value.rs
16
src/value.rs
|
@ -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,
|
||||
|
|
53
src/vm.rs
53
src/vm.rs
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user