grind on lifetimes, don't get it working

This commit is contained in:
Scott Richmond 2024-10-31 23:53:48 -04:00
parent 60f0a1081d
commit b77866baf9
4 changed files with 173 additions and 37 deletions

View File

@ -26,6 +26,7 @@
// * [ ] perf testing // * [ ] perf testing
use chumsky::{input::Stream, prelude::*}; use chumsky::{input::Stream, prelude::*};
use std::rc::Rc;
mod spans; mod spans;
@ -33,12 +34,16 @@ mod lexer;
use crate::lexer::*; use crate::lexer::*;
mod value; mod value;
use crate::value::*;
mod parser; mod parser;
use crate::parser::*; use crate::parser::*;
mod vm;
use crate::vm::*;
pub fn main() { 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(); let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if lex_errs.len() > 0 { if lex_errs.len() > 0 {
println!("{:?}", lex_errs); 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))) .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s)))
.unwrap(); .unwrap();
println!("{}", ast); 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)] // #[cfg(test)]

View File

@ -1,6 +1,5 @@
use crate::lexer::*; use crate::lexer::*;
use crate::spans::*; use crate::spans::*;
use crate::value::*;
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive}; use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
use std::fmt; use std::fmt;
@ -8,14 +7,18 @@ use std::fmt;
pub enum Ast<'src> { pub enum Ast<'src> {
Error, Error,
Placeholder, Placeholder,
Value(Value<'src>), Nil,
Boolean(bool),
Number(f64),
Keyword(&'src str),
Word(&'src str), Word(&'src str),
String(&'src str),
Block(Vec<Spanned<Self>>), Block(Vec<Spanned<Self>>),
If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>), If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>),
Tuple(Vec<Spanned<Self>>), Tuple(Vec<Spanned<Self>>),
Arguments(Vec<Spanned<Self>>), Arguments(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>), List(Vec<Spanned<Self>>),
Pair(Value<'src>, Box<Spanned<Self>>), Pair(&'src str, Box<Spanned<Self>>),
Dict(Vec<Spanned<Self>>), Dict(Vec<Spanned<Self>>),
Let(Box<Spanned<Pattern<'src>>>, Box<Spanned<Self>>), Let(Box<Spanned<Pattern<'src>>>, Box<Spanned<Self>>),
Box(&'src str, Box<Spanned<Self>>), Box(&'src str, Box<Spanned<Self>>),
@ -38,7 +41,11 @@ impl<'src> fmt::Display for Ast<'src> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Ast::Error => write!(f, "Error"), 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::Word(w) => write!(f, "Word: {}", w),
Ast::Block(b) => write!( Ast::Block(b) => write!(
f, f,
@ -99,21 +106,29 @@ impl<'src> fmt::Display for Ast<'src> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Pattern<'src> { pub enum Pattern<'src> {
Atom(Value<'src>), Nil,
Boolean(bool),
Number(f64),
String(&'src str),
Keyword(&'src str),
Word(&'src str), Word(&'src str),
Placeholder, Placeholder,
Tuple(Vec<Spanned<Self>>), Tuple(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>), List(Vec<Spanned<Self>>),
// is this the right representation for Dicts? // is this the right representation for Dicts?
// Could/should this also be a Vec? // Could/should this also be a Vec?
Pair(Value<'src>, Box<Spanned<Self>>), Pair(&'src str, Box<Spanned<Self>>),
Dict(Vec<Spanned<Self>>), Dict(Vec<Spanned<Self>>),
} }
impl<'src> fmt::Display for Pattern<'src> { impl<'src> fmt::Display for Pattern<'src> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { 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::Word(w) => write!(f, "{}", w),
Pattern::Placeholder => write!(f, "_"), Pattern::Placeholder => write!(f, "_"),
Pattern::Tuple(t) => write!( Pattern::Tuple(t) => write!(
@ -178,10 +193,10 @@ where
select! { Token::Word(w) => Pattern::Word(w) }.map_with(|w, e| (w, e.span())); select! { Token::Word(w) => Pattern::Word(w) }.map_with(|w, e| (w, e.span()));
let atom_pattern = select! { let atom_pattern = select! {
Token::Nil => Pattern::Atom(Value::Nil), Token::Nil => Pattern::Nil,
Token::Boolean(b) => Pattern::Atom(Value::Boolean(b)), Token::Boolean(b) => Pattern::Boolean(b),
Token::Number(n) => Pattern::Atom(Value::Number(n)), Token::Number(n) => Pattern::Number(n),
Token::Keyword(k) => Pattern::Atom(Value::Keyword(k)), Token::Keyword(k) => Pattern::Keyword(k),
} }
.map_with(|a, e| (a, e.span())); .map_with(|a, e| (a, e.span()));
@ -204,13 +219,13 @@ where
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
.map_with(|list, e| (Pattern::List(list), e.span())); .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()) .then(pattern.clone())
.map_with(|(kw, patt), e| (Pattern::Pair(kw, Box::new(patt)), e.span())); .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| { 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(), e.span(),
) )
}); });
@ -245,15 +260,14 @@ where
.labelled("word"); .labelled("word");
let value = select! { let value = select! {
Token::Nil => Ast::Value(Value::Nil), Token::Nil => Ast::Nil,
Token::Boolean(b) => Ast::Value(Value::Boolean(b)), Token::Boolean(b) => Ast::Boolean(b),
Token::Number(n) => Ast::Value(Value::Number(n)), Token::Number(n) => Ast::Number(n),
Token::String(s) => Ast::Value(Value::String(s)), Token::String(s) => Ast::String(s),
} }
.map_with(|v, e| (v, e.span())); .map_with(|v, e| (v, e.span()));
let keyword = select! {Token::Keyword(k) => Ast::Value(Value::Keyword(k)),} let keyword = select! {Token::Keyword(k) => Ast::Keyword(k),}.map_with(|k, e| (k, e.span()));
.map_with(|k, e| (k, e.span()));
let tuple = simple let tuple = simple
.clone() .clone()
@ -297,16 +311,12 @@ where
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
.map_with(|list, e| (Ast::List(list), e.span())); .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()) .then(simple.clone())
.map_with(|(kw, expr), e| (Ast::Pair(kw, Box::new(expr)), e.span())); .map_with(|(kw, expr), e| (Ast::Pair(kw, Box::new(expr)), e.span()));
let shorthand = select! {Token::Word(w) => w}.map_with(|w, e| { let shorthand = select! {Token::Word(w) => w}
( .map_with(|w, e| (Ast::Pair(w, Box::new((Ast::Word(w), e.span()))), e.span()));
Ast::Pair(Value::Keyword(w), Box::new((Ast::Word(w), e.span()))),
e.span(),
)
});
let dict = pair let dict = pair
.or(shorthand) .or(shorthand)

View File

@ -2,6 +2,7 @@ use crate::parser::*;
use crate::spans::*; use crate::spans::*;
use imbl::*; use imbl::*;
use std::fmt; use std::fmt;
use std::rc::Rc;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Clause<'src> { pub struct Clause<'src> {
@ -17,17 +18,20 @@ pub struct Fn<'src> {
body: Vec<Clause<'src>>, body: Vec<Clause<'src>>,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Value<'src> { pub enum Value {
Nil, Nil,
Boolean(bool), Boolean(bool),
Number(f64), Number(f64),
Keyword(&'src str), Keyword(&'static str),
String(&'src str), String(&'static str),
Tuple(Vec<Self>), // on the heap for now // on the heap for now
List(Vector<Self>), // ref-counted, immutable, persistent Tuple(Rc<Vec<Self>>),
Dict(HashMap<&'src str, Self>), // ref-counted, immutable, persistent // ref-counted, immutable, persistent
Fn(&'src Fn<'src>), List(Rc<Vector<Self>>),
// ref-counted, immutable, persistent
Dict(Rc<HashMap<&'static str, Self>>),
// Fn(Rc<Fn<'src>>),
// Set(HashSet<Self>), // Set(HashSet<Self>),
// Sets are hard // Sets are hard
// Sets require Eq // Sets require Eq
@ -40,7 +44,22 @@ pub enum Value<'src> {
// pkgs, nses, tests // 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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Value::Nil => write!(f, "nil"), Value::Nil => write!(f, "nil"),
@ -48,7 +67,7 @@ impl<'src> fmt::Display for Value<'src> {
Value::Number(n) => write!(f, "{}", n), Value::Number(n) => write!(f, "{}", n),
Value::Keyword(k) => write!(f, ":{}", k), Value::Keyword(k) => write!(f, ":{}", k),
Value::String(s) => write!(f, "\"{}\"", s), 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!( Value::Tuple(t) => write!(
f, 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,
}
}
}

View File

@ -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<Value, LudusError> {
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!(),
}
}