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
|
// * [ ] 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)]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
48
src/value.rs
48
src/value.rs
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
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