grind on lifetimes, don't get it working
This commit is contained in:
parent
60f0a1081d
commit
b77866baf9
16
src/main.rs
16
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)]
|
||||
|
|
|
@ -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<Spanned<Self>>),
|
||||
If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||||
Tuple(Vec<Spanned<Self>>),
|
||||
Arguments(Vec<Spanned<Self>>),
|
||||
List(Vec<Spanned<Self>>),
|
||||
Pair(Value<'src>, Box<Spanned<Self>>),
|
||||
Pair(&'src str, Box<Spanned<Self>>),
|
||||
Dict(Vec<Spanned<Self>>),
|
||||
Let(Box<Spanned<Pattern<'src>>>, 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 {
|
||||
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<Spanned<Self>>),
|
||||
List(Vec<Spanned<Self>>),
|
||||
// is this the right representation for Dicts?
|
||||
// Could/should this also be a Vec?
|
||||
Pair(Value<'src>, Box<Spanned<Self>>),
|
||||
Pair(&'src str, Box<Spanned<Self>>),
|
||||
Dict(Vec<Spanned<Self>>),
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
48
src/value.rs
48
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<Clause<'src>>,
|
||||
}
|
||||
|
||||
#[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<Self>), // on the heap for now
|
||||
List(Vector<Self>), // 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<Vec<Self>>),
|
||||
// ref-counted, immutable, persistent
|
||||
List(Rc<Vector<Self>>),
|
||||
// ref-counted, immutable, persistent
|
||||
Dict(Rc<HashMap<&'static str, Self>>),
|
||||
// Fn(Rc<Fn<'src>>),
|
||||
// Set(HashSet<Self>),
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
84
src/vm.rs
84
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<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!(),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user