move patterns, clauses into AST
This commit is contained in:
parent
cab1b3f173
commit
f5a6facb1c
104
src/base.rs
104
src/base.rs
|
@ -4,7 +4,7 @@ use ran::ran_f64;
|
|||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Base<'src> {
|
||||
pub enum BaseFn<'src> {
|
||||
Nullary(fn() -> Value<'src>),
|
||||
Unary(fn(&Value<'src>) -> Value<'src>),
|
||||
Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>),
|
||||
|
@ -572,59 +572,59 @@ pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> {
|
|||
|
||||
pub fn base<'src>() -> Vec<(String, Value<'src>)> {
|
||||
let members = vec![
|
||||
("add", Value::Base(Base::Binary(add))),
|
||||
("and", Value::Base(Base::Binary(and))),
|
||||
("append", Value::Base(Base::Binary(append))),
|
||||
("assoc", Value::Base(Base::Ternary(assoc))),
|
||||
("at", Value::Base(Base::Binary(at))),
|
||||
("atan_2", Value::Base(Base::Binary(atan_2))),
|
||||
("bool", Value::Base(Base::Unary(r#bool))),
|
||||
("ceil", Value::Base(Base::Unary(ceil))),
|
||||
("chars", Value::Base(Base::Unary(chars))),
|
||||
("concat", Value::Base(Base::Binary(concat))),
|
||||
("cos", Value::Base(Base::Unary(cos))),
|
||||
("count", Value::Base(Base::Unary(count))),
|
||||
("dec", Value::Base(Base::Unary(dec))),
|
||||
("dissoc", Value::Base(Base::Binary(dissoc))),
|
||||
("div", Value::Base(Base::Binary(div))),
|
||||
("doc!", Value::Base(Base::Unary(doc))),
|
||||
("downcase", Value::Base(Base::Unary(downcase))),
|
||||
("eq?", Value::Base(Base::Binary(eq))),
|
||||
("first", Value::Base(Base::Unary(first))),
|
||||
("floor", Value::Base(Base::Unary(floor))),
|
||||
("get", Value::Base(Base::Binary(get))),
|
||||
("gt?", Value::Base(Base::Binary(gt))),
|
||||
("gte?", Value::Base(Base::Binary(gte))),
|
||||
("inc", Value::Base(Base::Unary(inc))),
|
||||
("last", Value::Base(Base::Unary(last))),
|
||||
("list", Value::Base(Base::Unary(list))),
|
||||
("lt?", Value::Base(Base::Binary(lt))),
|
||||
("lte?", Value::Base(Base::Binary(lte))),
|
||||
("mod", Value::Base(Base::Binary(r#mod))),
|
||||
("mult", Value::Base(Base::Binary(mult))),
|
||||
("number", Value::Base(Base::Unary(number))),
|
||||
("or", Value::Base(Base::Binary(or))),
|
||||
("add", Value::Base(BaseFn::Binary(add))),
|
||||
("and", Value::Base(BaseFn::Binary(and))),
|
||||
("append", Value::Base(BaseFn::Binary(append))),
|
||||
("assoc", Value::Base(BaseFn::Ternary(assoc))),
|
||||
("at", Value::Base(BaseFn::Binary(at))),
|
||||
("atan_2", Value::Base(BaseFn::Binary(atan_2))),
|
||||
("bool", Value::Base(BaseFn::Unary(r#bool))),
|
||||
("ceil", Value::Base(BaseFn::Unary(ceil))),
|
||||
("chars", Value::Base(BaseFn::Unary(chars))),
|
||||
("concat", Value::Base(BaseFn::Binary(concat))),
|
||||
("cos", Value::Base(BaseFn::Unary(cos))),
|
||||
("count", Value::Base(BaseFn::Unary(count))),
|
||||
("dec", Value::Base(BaseFn::Unary(dec))),
|
||||
("dissoc", Value::Base(BaseFn::Binary(dissoc))),
|
||||
("div", Value::Base(BaseFn::Binary(div))),
|
||||
("doc!", Value::Base(BaseFn::Unary(doc))),
|
||||
("downcase", Value::Base(BaseFn::Unary(downcase))),
|
||||
("eq?", Value::Base(BaseFn::Binary(eq))),
|
||||
("first", Value::Base(BaseFn::Unary(first))),
|
||||
("floor", Value::Base(BaseFn::Unary(floor))),
|
||||
("get", Value::Base(BaseFn::Binary(get))),
|
||||
("gt?", Value::Base(BaseFn::Binary(gt))),
|
||||
("gte?", Value::Base(BaseFn::Binary(gte))),
|
||||
("inc", Value::Base(BaseFn::Unary(inc))),
|
||||
("last", Value::Base(BaseFn::Unary(last))),
|
||||
("list", Value::Base(BaseFn::Unary(list))),
|
||||
("lt?", Value::Base(BaseFn::Binary(lt))),
|
||||
("lte?", Value::Base(BaseFn::Binary(lte))),
|
||||
("mod", Value::Base(BaseFn::Binary(r#mod))),
|
||||
("mult", Value::Base(BaseFn::Binary(mult))),
|
||||
("number", Value::Base(BaseFn::Unary(number))),
|
||||
("or", Value::Base(BaseFn::Binary(or))),
|
||||
("pi", Value::Number(std::f64::consts::PI)),
|
||||
("print!", Value::Base(Base::Unary(print))),
|
||||
("random", Value::Base(Base::Nullary(random))),
|
||||
("range", Value::Base(Base::Binary(range))),
|
||||
("rest", Value::Base(Base::Unary(rest))),
|
||||
("round", Value::Base(Base::Unary(round))),
|
||||
("show", Value::Base(Base::Unary(show))),
|
||||
("sin", Value::Base(Base::Unary(sin))),
|
||||
("slice", Value::Base(Base::Ternary(slice))),
|
||||
("split", Value::Base(Base::Binary(split))),
|
||||
("sqrt", Value::Base(Base::Unary(sqrt))),
|
||||
("print!", Value::Base(BaseFn::Unary(print))),
|
||||
("random", Value::Base(BaseFn::Nullary(random))),
|
||||
("range", Value::Base(BaseFn::Binary(range))),
|
||||
("rest", Value::Base(BaseFn::Unary(rest))),
|
||||
("round", Value::Base(BaseFn::Unary(round))),
|
||||
("show", Value::Base(BaseFn::Unary(show))),
|
||||
("sin", Value::Base(BaseFn::Unary(sin))),
|
||||
("slice", Value::Base(BaseFn::Ternary(slice))),
|
||||
("split", Value::Base(BaseFn::Binary(split))),
|
||||
("sqrt", Value::Base(BaseFn::Unary(sqrt))),
|
||||
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
||||
("store!", Value::Base(Base::Binary(store))),
|
||||
("sub", Value::Base(Base::Binary(sub))),
|
||||
("tan", Value::Base(Base::Unary(tan))),
|
||||
("trim", Value::Base(Base::Unary(trim))),
|
||||
("triml", Value::Base(Base::Unary(triml))),
|
||||
("trimr", Value::Base(Base::Unary(trimr))),
|
||||
("type", Value::Base(Base::Unary(r#type))),
|
||||
("unbox", Value::Base(Base::Unary(unbox))),
|
||||
("upcase", Value::Base(Base::Unary(upcase))),
|
||||
("store!", Value::Base(BaseFn::Binary(store))),
|
||||
("sub", Value::Base(BaseFn::Binary(sub))),
|
||||
("tan", Value::Base(BaseFn::Unary(tan))),
|
||||
("trim", Value::Base(BaseFn::Unary(trim))),
|
||||
("triml", Value::Base(BaseFn::Unary(triml))),
|
||||
("trimr", Value::Base(BaseFn::Unary(trimr))),
|
||||
("type", Value::Base(BaseFn::Unary(r#type))),
|
||||
("unbox", Value::Base(BaseFn::Unary(unbox))),
|
||||
("upcase", Value::Base(BaseFn::Unary(upcase))),
|
||||
];
|
||||
let pkg = Value::Dict(HashMap::from(members));
|
||||
vec![("base".to_string(), pkg)]
|
||||
|
|
156
src/context.rs
156
src/context.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::base::*;
|
||||
use crate::parser::*;
|
||||
use crate::spans::*;
|
||||
use crate::value::{Fn, Value};
|
||||
use imbl::HashMap;
|
||||
use imbl::Vector;
|
||||
|
@ -71,16 +72,17 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn match_pattern(&mut self, patt: &Pattern, val: &Value<'src>) -> Option<&Context<'src>> {
|
||||
pub fn match_pattern(&mut self, patt: &Ast, val: &Value<'src>) -> Option<&Context<'src>> {
|
||||
use Ast::*;
|
||||
match (patt, val) {
|
||||
(Pattern::Nil, Value::Nil) => Some(self),
|
||||
(Pattern::Placeholder, _) => Some(self),
|
||||
(Pattern::Number(x), Value::Number(y)) => self.match_eq(x, y),
|
||||
(Pattern::Boolean(x), Value::Boolean(y)) => self.match_eq(x, y),
|
||||
(Pattern::Keyword(x), Value::Keyword(y)) => self.match_eq(x, y),
|
||||
(Pattern::String(x), Value::InternedString(y)) => self.match_eq(x, y),
|
||||
(Pattern::String(x), Value::AllocatedString(y)) => self.match_eq(&x.to_string(), y),
|
||||
(Pattern::Interpolated(_, StringMatcher(matcher)), Value::InternedString(y)) => {
|
||||
(NilPattern, Value::Nil) => Some(self),
|
||||
(PlaceholderPattern, _) => Some(self),
|
||||
(NumberPattern(x), Value::Number(y)) => self.match_eq(x, y),
|
||||
(BooleanPattern(x), Value::Boolean(y)) => self.match_eq(x, y),
|
||||
(KeywordPattern(x), Value::Keyword(y)) => self.match_eq(x, y),
|
||||
(StringPattern(x), Value::InternedString(y)) => self.match_eq(x, y),
|
||||
(StringPattern(x), Value::AllocatedString(y)) => self.match_eq(&x.to_string(), y),
|
||||
(InterpolatedPattern(_, StringMatcher(matcher)), Value::InternedString(y)) => {
|
||||
match matcher(y.to_string()) {
|
||||
Some(matches) => {
|
||||
let mut matches = matches
|
||||
|
@ -98,11 +100,11 @@ impl<'src> Context<'src> {
|
|||
None => None,
|
||||
}
|
||||
}
|
||||
(Pattern::Word(w), val) => {
|
||||
(WordPattern(w), val) => {
|
||||
self.bind(w.to_string(), &val);
|
||||
Some(self)
|
||||
}
|
||||
(Pattern::As(word, type_str), value) => {
|
||||
(AsPattern(word, type_str), value) => {
|
||||
let ludus_type = r#type(value);
|
||||
let type_kw = Value::Keyword(type_str);
|
||||
if type_kw == ludus_type {
|
||||
|
@ -112,16 +114,14 @@ impl<'src> Context<'src> {
|
|||
None
|
||||
}
|
||||
}
|
||||
(Pattern::Tuple(x), Value::Tuple(y)) => {
|
||||
let has_splat = x
|
||||
.iter()
|
||||
.any(|patt| matches!(patt, (Pattern::Splattern(_), _)));
|
||||
(TuplePattern(x), Value::Tuple(y)) => {
|
||||
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
|
||||
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
|
||||
return None;
|
||||
};
|
||||
let to = self.locals.len();
|
||||
for i in 0..x.len() {
|
||||
if let Pattern::Splattern(patt) = &x[i].0 {
|
||||
if let Splattern(patt) = &x[i].0 {
|
||||
let mut list = Vector::new();
|
||||
for i in i..y.len() {
|
||||
list.push_back(y[i].clone())
|
||||
|
@ -135,16 +135,14 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
Some(self)
|
||||
}
|
||||
(Pattern::List(x), Value::List(y)) => {
|
||||
let has_splat = x
|
||||
.iter()
|
||||
.any(|patt| matches!(patt, (Pattern::Splattern(_), _)));
|
||||
(ListPattern(x), Value::List(y)) => {
|
||||
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
|
||||
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
|
||||
return None;
|
||||
};
|
||||
let to = self.locals.len();
|
||||
for (i, (patt, _)) in x.iter().enumerate() {
|
||||
if let Pattern::Splattern(patt) = &patt {
|
||||
if let Splattern(patt) = &patt {
|
||||
let list = Value::List(y.skip(i));
|
||||
self.match_pattern(&patt.0, &list);
|
||||
} else if self.match_pattern(patt, y.get(i).unwrap()).is_none() {
|
||||
|
@ -157,10 +155,8 @@ impl<'src> Context<'src> {
|
|||
// TODO: optimize this on several levels
|
||||
// - [ ] opportunistic mutation
|
||||
// - [ ] get rid of all the pointer indirection in word splats
|
||||
(Pattern::Dict(x), Value::Dict(y)) => {
|
||||
let has_splat = x
|
||||
.iter()
|
||||
.any(|patt| matches!(patt, (Pattern::Splattern(_), _)));
|
||||
(DictPattern(x), Value::Dict(y)) => {
|
||||
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
|
||||
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
|
||||
return None;
|
||||
};
|
||||
|
@ -168,7 +164,7 @@ impl<'src> Context<'src> {
|
|||
let mut matched = vec![];
|
||||
for (pattern, _) in x {
|
||||
match pattern {
|
||||
Pattern::Pair(key, patt) => {
|
||||
PairPattern(key, patt) => {
|
||||
if let Some(val) = y.get(key) {
|
||||
if self.match_pattern(&patt.0, val).is_none() {
|
||||
self.pop_to(to);
|
||||
|
@ -180,8 +176,8 @@ impl<'src> Context<'src> {
|
|||
return None;
|
||||
};
|
||||
}
|
||||
Pattern::Splattern(pattern) => match pattern.0 {
|
||||
Pattern::Word(w) => {
|
||||
Splattern(pattern) => match pattern.0 {
|
||||
WordPattern(w) => {
|
||||
// TODO: find a way to take ownership
|
||||
// this will ALWAYS make structural changes, because of this clone
|
||||
// we want opportunistic mutation if possible
|
||||
|
@ -191,7 +187,7 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
self.bind(w.to_string(), &Value::Dict(unmatched));
|
||||
}
|
||||
Pattern::Placeholder => (),
|
||||
PlaceholderPattern => (),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
|
@ -206,14 +202,15 @@ impl<'src> Context<'src> {
|
|||
pub fn match_clauses(
|
||||
&mut self,
|
||||
value: &Value<'src>,
|
||||
clauses: &'src [MatchClause],
|
||||
clauses: &'src [Spanned<Ast>],
|
||||
) -> LResult<'src> {
|
||||
{
|
||||
let parent = self.ast;
|
||||
let to = self.locals.len();
|
||||
for MatchClause { patt, body, guard } in clauses.iter() {
|
||||
let mut clauses = clauses.iter();
|
||||
while let Some((Ast::MatchClause(patt, guard, body), _)) = clauses.next() {
|
||||
if let Some(_) = self.match_pattern(&patt.0, value) {
|
||||
let pass_guard = match guard {
|
||||
let pass_guard = match guard.as_ref() {
|
||||
None => true,
|
||||
Some((ast, _)) => {
|
||||
self.ast = ast;
|
||||
|
@ -240,30 +237,31 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
|
||||
pub fn apply(&mut self, callee: Value<'src>, caller: Value<'src>) -> LResult<'src> {
|
||||
use Value::*;
|
||||
match (callee, caller) {
|
||||
(Value::Keyword(kw), Value::Dict(dict)) => {
|
||||
(Keyword(kw), Dict(dict)) => {
|
||||
if let Some(val) = dict.get(kw) {
|
||||
Ok(val.clone())
|
||||
} else {
|
||||
Ok(Value::Nil)
|
||||
Ok(Nil)
|
||||
}
|
||||
}
|
||||
(Value::Dict(dict), Value::Keyword(kw)) => {
|
||||
(Dict(dict), Keyword(kw)) => {
|
||||
if let Some(val) = dict.get(kw) {
|
||||
Ok(val.clone())
|
||||
} else {
|
||||
Ok(Value::Nil)
|
||||
Ok(Nil)
|
||||
}
|
||||
}
|
||||
(Value::Fn(f), Value::Tuple(args)) => {
|
||||
let args = Value::Tuple(args);
|
||||
(Fn(f), Tuple(args)) => {
|
||||
let args = Tuple(args);
|
||||
self.match_clauses(&args, f.body)
|
||||
}
|
||||
(Value::Fn(_f), Value::Args(_args)) => todo!(),
|
||||
(_, Value::Keyword(_)) => Ok(Value::Nil),
|
||||
(_, Value::Args(_)) => Err(LErr::new(format!("you may only call a function"))),
|
||||
(Value::Base(f), Value::Tuple(args)) => match f {
|
||||
Base::Nullary(f) => {
|
||||
(Fn(_f), Args(_args)) => todo!(),
|
||||
(_, Keyword(_)) => Ok(Nil),
|
||||
(_, Args(_)) => Err(LErr::new(format!("you may only call a function"))),
|
||||
(Base(f), Tuple(args)) => match f {
|
||||
BaseFn::Nullary(f) => {
|
||||
let num_args = args.len();
|
||||
if num_args != 0 {
|
||||
Err(LErr::new(format!(
|
||||
|
@ -273,7 +271,7 @@ impl<'src> Context<'src> {
|
|||
Ok(f())
|
||||
}
|
||||
}
|
||||
Base::Unary(f) => {
|
||||
BaseFn::Unary(f) => {
|
||||
let num_args = args.len();
|
||||
if num_args != 1 {
|
||||
Err(LErr::new(format!(
|
||||
|
@ -283,7 +281,7 @@ impl<'src> Context<'src> {
|
|||
Ok(f(&args[0]))
|
||||
}
|
||||
}
|
||||
Base::Binary(r#fn) => {
|
||||
BaseFn::Binary(r#fn) => {
|
||||
let num_args = args.len();
|
||||
if num_args != 2 {
|
||||
Err(LErr::new(format!(
|
||||
|
@ -293,7 +291,7 @@ impl<'src> Context<'src> {
|
|||
Ok(r#fn(&args[0], &args[1]))
|
||||
}
|
||||
}
|
||||
Base::Ternary(f) => {
|
||||
BaseFn::Ternary(f) => {
|
||||
let num_args = args.len();
|
||||
if num_args != 3 {
|
||||
Err(LErr::new(format!(
|
||||
|
@ -309,15 +307,16 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
|
||||
pub fn eval(&mut self) -> LResult<'src> {
|
||||
use Ast::*;
|
||||
let root = self.ast;
|
||||
let result = match self.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)),
|
||||
Ast::String(s) => Ok(Value::InternedString(s)),
|
||||
Ast::Interpolated(parts) => {
|
||||
let mut interpolated = String::new();
|
||||
Nil => Ok(Value::Nil),
|
||||
Boolean(b) => Ok(Value::Boolean(*b)),
|
||||
Number(n) => Ok(Value::Number(*n)),
|
||||
Keyword(k) => Ok(Value::Keyword(k)),
|
||||
String(s) => Ok(Value::InternedString(s)),
|
||||
Interpolated(parts) => {
|
||||
let mut interpolated = std::string::String::new();
|
||||
for part in parts {
|
||||
match &part.0 {
|
||||
StringPart::Data(s) => interpolated.push_str(s.as_str()),
|
||||
|
@ -330,7 +329,7 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
Ok(Value::AllocatedString(Rc::new(interpolated)))
|
||||
}
|
||||
Ast::Block(exprs) => {
|
||||
Block(exprs) => {
|
||||
let parent = self.ast;
|
||||
let to = self.locals.len();
|
||||
let mut result = Value::Nil;
|
||||
|
@ -342,7 +341,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(result)
|
||||
}
|
||||
Ast::If(cond, if_true, if_false) => {
|
||||
If(cond, if_true, if_false) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &cond.0;
|
||||
let truthy = self.eval()?.bool();
|
||||
|
@ -351,7 +350,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
result
|
||||
}
|
||||
Ast::List(members) => {
|
||||
List(members) => {
|
||||
let parent = self.ast;
|
||||
let mut vect = Vector::new();
|
||||
for member in members {
|
||||
|
@ -373,7 +372,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(Value::List(vect))
|
||||
}
|
||||
Ast::Tuple(members) => {
|
||||
Tuple(members) => {
|
||||
let parent = self.ast;
|
||||
let mut vect = Vec::new();
|
||||
for member in members {
|
||||
|
@ -383,11 +382,11 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(Value::Tuple(Rc::new(vect)))
|
||||
}
|
||||
Ast::Word(w) | Ast::Splat(w) => {
|
||||
Word(w) | Ast::Splat(w) => {
|
||||
let val = self.resolve(&w.to_string())?;
|
||||
Ok(val)
|
||||
}
|
||||
Ast::Let(patt, expr) => {
|
||||
Let(patt, expr) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &expr.0;
|
||||
let val = self.eval()?;
|
||||
|
@ -398,9 +397,8 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
result
|
||||
}
|
||||
Ast::Placeholder => Ok(Value::Placeholder),
|
||||
Ast::Error => unreachable!(),
|
||||
Ast::Arguments(a) => {
|
||||
Placeholder => Ok(Value::Placeholder),
|
||||
Arguments(a) => {
|
||||
let parent = self.ast;
|
||||
let mut args = vec![];
|
||||
for (arg, _) in a.iter() {
|
||||
|
@ -416,7 +414,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
result
|
||||
}
|
||||
Ast::Dict(terms) => {
|
||||
Dict(terms) => {
|
||||
let parent = self.ast;
|
||||
let mut dict = HashMap::new();
|
||||
for term in terms {
|
||||
|
@ -441,7 +439,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(Value::Dict(dict))
|
||||
}
|
||||
Ast::LBox(name, expr) => {
|
||||
LBox(name, expr) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &expr.0;
|
||||
let val = self.eval()?;
|
||||
|
@ -450,7 +448,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(boxed)
|
||||
}
|
||||
Ast::Synthetic(root, first, rest) => {
|
||||
Synthetic(root, first, rest) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &root.0;
|
||||
let root = self.eval()?;
|
||||
|
@ -465,10 +463,12 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(curr)
|
||||
}
|
||||
Ast::When(clauses) => {
|
||||
When(clauses) => {
|
||||
let parent = self.ast;
|
||||
for clause in clauses.iter() {
|
||||
let WhenClause { cond, body } = &clause.0;
|
||||
let WhenClause(cond, body) = &clause.0 else {
|
||||
unreachable!()
|
||||
};
|
||||
self.ast = &cond.0;
|
||||
if self.eval()?.bool() {
|
||||
self.ast = &body.0;
|
||||
|
@ -479,7 +479,7 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
Err(LErr::new(format!("no match")))
|
||||
}
|
||||
Ast::Match(value, clauses) => {
|
||||
Match(value, clauses) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &value.0;
|
||||
let value = self.eval()?;
|
||||
|
@ -487,9 +487,9 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
result
|
||||
}
|
||||
Ast::Fn(name, clauses, doc) => {
|
||||
Fn(name, clauses, doc) => {
|
||||
let doc = doc.map(|s| s.to_string());
|
||||
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
|
||||
let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> {
|
||||
name: name.to_string(),
|
||||
body: clauses,
|
||||
doc,
|
||||
|
@ -497,13 +497,13 @@ impl<'src> Context<'src> {
|
|||
self.bind(name.to_string(), &the_fn);
|
||||
Ok(the_fn)
|
||||
}
|
||||
Ast::FnDeclaration(_name) => Ok(Value::Nil),
|
||||
Ast::Panic(msg) => {
|
||||
FnDeclaration(_name) => Ok(Value::Nil),
|
||||
Panic(msg) => {
|
||||
self.ast = &msg.0;
|
||||
let msg = self.eval()?;
|
||||
Err(LErr::new(format!("{msg}")))
|
||||
}
|
||||
Ast::Repeat(times, body) => {
|
||||
Repeat(times, body) => {
|
||||
let parent = self.ast;
|
||||
self.ast = ×.0;
|
||||
let times_num = match self.eval() {
|
||||
|
@ -517,7 +517,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
Ast::Do(terms) => {
|
||||
Do(terms) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &terms[0].0;
|
||||
let mut result = self.eval()?;
|
||||
|
@ -530,10 +530,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(result)
|
||||
}
|
||||
Ast::Pair(..) => {
|
||||
unreachable!()
|
||||
}
|
||||
Ast::Loop(init, clauses) => {
|
||||
Loop(init, clauses) => {
|
||||
let parent = self.ast;
|
||||
self.ast = &init.0;
|
||||
let mut args = self.eval()?;
|
||||
|
@ -547,7 +544,7 @@ impl<'src> Context<'src> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ast::Recur(args) => {
|
||||
Recur(args) => {
|
||||
let parent = self.ast;
|
||||
let mut vect = Vec::new();
|
||||
for arg in args {
|
||||
|
@ -557,6 +554,7 @@ impl<'src> Context<'src> {
|
|||
self.ast = parent;
|
||||
Ok(Value::Recur(vect))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.ast = root;
|
||||
result
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -150,26 +150,25 @@ pub fn run(src: &'static str) {
|
|||
|
||||
let mut valxor = validator::Validator::new(&ast, span, &dummy_prelude);
|
||||
|
||||
valxor.validate();
|
||||
// valxor.validate();
|
||||
|
||||
dbg!(valxor);
|
||||
// dbg!(valxor);
|
||||
|
||||
// let mut ctx = prelude();
|
||||
// ctx.ast = *
|
||||
let mut ctx = prelude();
|
||||
ctx.ast = *
|
||||
|
||||
// let result = ctx.eval();
|
||||
let result = ctx.eval();
|
||||
|
||||
// match result {
|
||||
// Ok(result) => println!("{}", result),
|
||||
// Err(LErr { msg, .. }) => println!("Errors!\n{}", msg),
|
||||
// }
|
||||
match result {
|
||||
Ok(result) => println!("{}", result),
|
||||
Err(LErr { msg, .. }) => println!("Errors!\n{}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let src = "
|
||||
loop () with {
|
||||
() -> :baz
|
||||
}
|
||||
let #{:a (x, y), :b [1, 2, (a, b)]} = #{:a (1, 2), :b [1, 2, (7, 8)]}
|
||||
(x, y, a, b)
|
||||
";
|
||||
run(src);
|
||||
// struct_scalpel::print_dissection_info::<value::Value>()
|
||||
|
|
|
@ -470,6 +470,7 @@ impl<'a> Validator<'a> {
|
|||
}
|
||||
// terminals can never be invalid
|
||||
Ast::Nil | Ast::Boolean(_) | Ast::Number(_) | Ast::Keyword(_) | Ast::String(_) => (),
|
||||
_ => todo!(),
|
||||
};
|
||||
self.ast = root;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::base::*;
|
||||
use crate::parser::*;
|
||||
use crate::spans::*;
|
||||
use imbl::*;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
|
@ -9,7 +10,7 @@ use struct_scalpel::Dissectible;
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Fn<'src> {
|
||||
pub name: String,
|
||||
pub body: &'src Vec<MatchClause>,
|
||||
pub body: &'src Vec<Spanned<Ast>>,
|
||||
pub doc: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ pub enum Value<'src> {
|
|||
Dict(HashMap<&'static str, Self>),
|
||||
Box(&'static str, Rc<RefCell<Self>>),
|
||||
Fn(Rc<Fn<'src>>),
|
||||
Base(Base<'src>),
|
||||
Base(BaseFn<'src>),
|
||||
Recur(Vec<Self>),
|
||||
// Set(HashSet<Self>),
|
||||
// Sets are hard
|
||||
|
|
Loading…
Reference in New Issue
Block a user