From b77866baf96a8dac3c05029a0559e2f0fe44f4b6 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Thu, 31 Oct 2024 23:53:48 -0400 Subject: [PATCH] grind on lifetimes, don't get it working --- src/main.rs | 16 +++++++++- src/parser.rs | 62 +++++++++++++++++++++---------------- src/value.rs | 48 +++++++++++++++++++++++------ src/vm.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 37 deletions(-) diff --git a/src/main.rs b/src/main.rs index af2f32a..c8682d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ // * [ ] perf testing use chumsky::{input::Stream, prelude::*}; +use std::rc::Rc; mod spans; @@ -33,12 +34,16 @@ mod lexer; use crate::lexer::*; mod value; +use crate::value::*; mod parser; use crate::parser::*; +mod vm; +use crate::vm::*; + pub fn main() { - let src = "let #{a, :b b} = foo\na(b(c),d)"; + let src = "(1, :two, nil)"; let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); if lex_errs.len() > 0 { println!("{:?}", lex_errs); @@ -53,6 +58,15 @@ pub fn main() { .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s))) .unwrap(); println!("{}", ast); + + let mut ctx = Ctx { + local_names: vec!["foo"], + local_values: vec![Value::Keyword("foo")], + }; + + let result = eval(ast, &mut ctx).unwrap(); + + println!("{}", result); } // #[cfg(test)] diff --git a/src/parser.rs b/src/parser.rs index b1896ac..e087a39 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,5 @@ use crate::lexer::*; use crate::spans::*; -use crate::value::*; use chumsky::{input::ValueInput, prelude::*, recursive::Recursive}; use std::fmt; @@ -8,14 +7,18 @@ use std::fmt; pub enum Ast<'src> { Error, Placeholder, - Value(Value<'src>), + Nil, + Boolean(bool), + Number(f64), + Keyword(&'src str), Word(&'src str), + String(&'src str), Block(Vec>), If(Box>, Box>, Box>), Tuple(Vec>), Arguments(Vec>), List(Vec>), - Pair(Value<'src>, Box>), + Pair(&'src str, Box>), Dict(Vec>), Let(Box>>, Box>), Box(&'src str, Box>), @@ -38,7 +41,11 @@ impl<'src> fmt::Display for Ast<'src> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Ast::Error => write!(f, "Error"), - Ast::Value(v) => write!(f, "Value: {}", v), + Ast::Nil => write!(f, "nil"), + Ast::String(s) => write!(f, "String: \"{}\"", s), + Ast::Boolean(b) => write!(f, "Boolean: {}", b), + Ast::Number(n) => write!(f, "Number: {}", n), + Ast::Keyword(k) => write!(f, "Keyword: :{}", k), Ast::Word(w) => write!(f, "Word: {}", w), Ast::Block(b) => write!( f, @@ -99,21 +106,29 @@ impl<'src> fmt::Display for Ast<'src> { #[derive(Clone, Debug, PartialEq)] pub enum Pattern<'src> { - Atom(Value<'src>), + Nil, + Boolean(bool), + Number(f64), + String(&'src str), + Keyword(&'src str), Word(&'src str), Placeholder, Tuple(Vec>), List(Vec>), // is this the right representation for Dicts? // Could/should this also be a Vec? - Pair(Value<'src>, Box>), + Pair(&'src str, Box>), Dict(Vec>), } impl<'src> fmt::Display for Pattern<'src> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Pattern::Atom(a) => write!(f, "{}", a), + Pattern::Nil => write!(f, "nil"), + Pattern::Boolean(b) => write!(f, "{}", b), + Pattern::Number(n) => write!(f, "{}", n), + Pattern::String(s) => write!(f, "{}", s), + Pattern::Keyword(k) => write!(f, ":{}", k), Pattern::Word(w) => write!(f, "{}", w), Pattern::Placeholder => write!(f, "_"), Pattern::Tuple(t) => write!( @@ -178,10 +193,10 @@ where select! { Token::Word(w) => Pattern::Word(w) }.map_with(|w, e| (w, e.span())); let atom_pattern = select! { - Token::Nil => Pattern::Atom(Value::Nil), - Token::Boolean(b) => Pattern::Atom(Value::Boolean(b)), - Token::Number(n) => Pattern::Atom(Value::Number(n)), - Token::Keyword(k) => Pattern::Atom(Value::Keyword(k)), + Token::Nil => Pattern::Nil, + Token::Boolean(b) => Pattern::Boolean(b), + Token::Number(n) => Pattern::Number(n), + Token::Keyword(k) => Pattern::Keyword(k), } .map_with(|a, e| (a, e.span())); @@ -204,13 +219,13 @@ where .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .map_with(|list, e| (Pattern::List(list), e.span())); - let pair_pattern = select! {Token::Keyword(k) => Value::Keyword(k)} + let pair_pattern = select! {Token::Keyword(k) => k} .then(pattern.clone()) .map_with(|(kw, patt), e| (Pattern::Pair(kw, Box::new(patt)), e.span())); let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| { ( - Pattern::Pair(Value::Keyword(w), Box::new((Pattern::Word(w), e.span()))), + Pattern::Pair(w, Box::new((Pattern::Word(w), e.span()))), e.span(), ) }); @@ -245,15 +260,14 @@ where .labelled("word"); let value = select! { - Token::Nil => Ast::Value(Value::Nil), - Token::Boolean(b) => Ast::Value(Value::Boolean(b)), - Token::Number(n) => Ast::Value(Value::Number(n)), - Token::String(s) => Ast::Value(Value::String(s)), + Token::Nil => Ast::Nil, + Token::Boolean(b) => Ast::Boolean(b), + Token::Number(n) => Ast::Number(n), + Token::String(s) => Ast::String(s), } .map_with(|v, e| (v, e.span())); - let keyword = select! {Token::Keyword(k) => Ast::Value(Value::Keyword(k)),} - .map_with(|k, e| (k, e.span())); + let keyword = select! {Token::Keyword(k) => Ast::Keyword(k),}.map_with(|k, e| (k, e.span())); let tuple = simple .clone() @@ -297,16 +311,12 @@ where .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .map_with(|list, e| (Ast::List(list), e.span())); - let pair = select! {Token::Keyword(k) => Value::Keyword(k)} + let pair = select! {Token::Keyword(k) => k} .then(simple.clone()) .map_with(|(kw, expr), e| (Ast::Pair(kw, Box::new(expr)), e.span())); - let shorthand = select! {Token::Word(w) => w}.map_with(|w, e| { - ( - Ast::Pair(Value::Keyword(w), Box::new((Ast::Word(w), e.span()))), - e.span(), - ) - }); + let shorthand = select! {Token::Word(w) => w} + .map_with(|w, e| (Ast::Pair(w, Box::new((Ast::Word(w), e.span()))), e.span())); let dict = pair .or(shorthand) diff --git a/src/value.rs b/src/value.rs index ac8b3a0..9783a41 100644 --- a/src/value.rs +++ b/src/value.rs @@ -2,6 +2,7 @@ use crate::parser::*; use crate::spans::*; use imbl::*; use std::fmt; +use std::rc::Rc; #[derive(Clone, Debug, PartialEq)] pub struct Clause<'src> { @@ -17,17 +18,20 @@ pub struct Fn<'src> { body: Vec>, } -#[derive(Clone, Debug, PartialEq)] -pub enum Value<'src> { +#[derive(Debug, PartialEq)] +pub enum Value { Nil, Boolean(bool), Number(f64), - Keyword(&'src str), - String(&'src str), - Tuple(Vec), // on the heap for now - List(Vector), // ref-counted, immutable, persistent - Dict(HashMap<&'src str, Self>), // ref-counted, immutable, persistent - Fn(&'src Fn<'src>), + Keyword(&'static str), + String(&'static str), + // on the heap for now + Tuple(Rc>), + // ref-counted, immutable, persistent + List(Rc>), + // ref-counted, immutable, persistent + Dict(Rc>), + // Fn(Rc>), // Set(HashSet), // Sets are hard // Sets require Eq @@ -40,7 +44,22 @@ pub enum Value<'src> { // pkgs, nses, tests } -impl<'src> fmt::Display for Value<'src> { +impl<'src> Clone for Value { + fn clone(&self) -> Value { + match self { + Value::Nil => Value::Nil, + Value::Boolean(b) => Value::Boolean(b.clone()), + Value::String(s) => Value::String(s), + Value::Keyword(s) => Value::Keyword(s), + Value::Number(n) => Value::Number(n.clone()), + Value::Tuple(t) => Value::Tuple(t.clone()), + Value::List(l) => Value::List(l.clone()), + Value::Dict(d) => Value::Dict(d.clone()), + } + } +} + +impl<'src> fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Value::Nil => write!(f, "nil"), @@ -48,7 +67,7 @@ impl<'src> fmt::Display for Value<'src> { Value::Number(n) => write!(f, "{}", n), Value::Keyword(k) => write!(f, ":{}", k), Value::String(s) => write!(f, "\"{}\"", s), - Value::Fn(fun) => write!(f, "fn {}", fun.name), + // Value::Fn(fun) => write!(f, "fn {}", fun.name), Value::Tuple(t) => write!( f, "({})", @@ -69,3 +88,12 @@ impl<'src> fmt::Display for Value<'src> { } } } + +impl Value { + pub fn bool(&self) -> bool { + match self { + Value::Nil | Value::Boolean(false) => false, + _ => true, + } + } +} diff --git a/src/vm.rs b/src/vm.rs index e69de29..b312faa 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -0,0 +1,84 @@ +use crate::parser::*; +use crate::value::*; +use imbl::Vector; +use std::rc::Rc; + +#[derive(Clone, Debug)] +pub struct LudusError { + msg: String, +} + +// oy +// lifetimes are a mess +// I need 'src kind of everywhere +// But (maybe) using 'src in eval +// for ctx +// means I can't borrow it mutably +// I guess the question is how to get +// 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)>, +} + +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; + } + } + 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 { + match ast { + Ast::Nil => Ok(Value::Nil), + 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) => { + let mut result = Value::Nil; + for (expr, _) in exprs { + result = eval(expr, ctx)?; + } + Ok(result) + } + Ast::If(cond, if_true, if_false) => { + let truthy = eval((*cond).0, ctx)?.bool(); + if truthy { + let (if_true, _) = *if_true; + eval(if_true, ctx) + } else { + 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)?) + } + Ok(Value::List(Rc::new(vect))) + } + Ast::Tuple(members) => { + let mut vect = Vec::new(); + for member in members { + vect.push(eval(member.0, ctx)?); + } + Ok(Value::Tuple(Rc::new(vect))) + } + Ast::Word(w) => Ok(ctx.resolve(w)), + _ => todo!(), + } +}