work on functions, discover recursion problems
This commit is contained in:
parent
d4af160f80
commit
8a9170b002
|
@ -50,8 +50,8 @@ pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> {
|
||||||
pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
|
pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
|
||||||
match f {
|
match f {
|
||||||
Value::Fn(f) => {
|
Value::Fn(f) => {
|
||||||
let name = &f.borrow().name;
|
let name = &f.name;
|
||||||
let doc = &f.borrow().doc;
|
let doc = &f.doc;
|
||||||
if let Some(docstr) = doc {
|
if let Some(docstr) = doc {
|
||||||
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
|
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub fn report_panic(err: LErr) {
|
||||||
let Value::Fn(f) = function else {
|
let Value::Fn(f) = function else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let fn_name = f.borrow().name.clone();
|
let fn_name = f.name.clone();
|
||||||
let i = first_span.start;
|
let i = first_span.start;
|
||||||
let j = second_span.end;
|
let j = second_span.end;
|
||||||
let label = Label::new((entry.input, i..j))
|
let label = Label::new((entry.input, i..j))
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -94,14 +94,14 @@ pub fn prelude<'src>() -> (
|
||||||
}
|
}
|
||||||
|
|
||||||
let prelude_parsed = Box::leak(Box::new(p_ast.unwrap()));
|
let prelude_parsed = Box::leak(Box::new(p_ast.unwrap()));
|
||||||
let base_pkg = base();
|
let base_pkg = Box::leak(Box::new(base()));
|
||||||
|
|
||||||
let mut v6or = Validator::new(
|
let mut v6or = Validator::new(
|
||||||
&prelude_parsed.0,
|
&prelude_parsed.0,
|
||||||
prelude_parsed.1,
|
prelude_parsed.1,
|
||||||
"prelude",
|
"prelude",
|
||||||
prelude,
|
prelude,
|
||||||
&base_pkg,
|
base_pkg,
|
||||||
);
|
);
|
||||||
v6or.validate();
|
v6or.validate();
|
||||||
|
|
||||||
|
@ -110,13 +110,15 @@ pub fn prelude<'src>() -> (
|
||||||
panic!("interal Ludus error: invalid prelude")
|
panic!("interal Ludus error: invalid prelude")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let static_vec = Box::leak(Box::new(vec![]));
|
||||||
|
|
||||||
let mut base_ctx = Process::<'src> {
|
let mut base_ctx = Process::<'src> {
|
||||||
input: "prelude",
|
input: "prelude",
|
||||||
src: prelude,
|
src: prelude,
|
||||||
locals: base_pkg.clone(),
|
locals: base_pkg.clone(),
|
||||||
ast: &prelude_parsed.0,
|
ast: &prelude_parsed.0,
|
||||||
span: prelude_parsed.1,
|
span: prelude_parsed.1,
|
||||||
prelude: vec![],
|
prelude: static_vec,
|
||||||
fn_info: v6or.fn_info,
|
fn_info: v6or.fn_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,8 +166,9 @@ pub fn run(src: &'static str) {
|
||||||
let parsed = parse_result.unwrap();
|
let parsed = parse_result.unwrap();
|
||||||
|
|
||||||
let (prelude_ctx, mut prelude_fn_info) = prelude();
|
let (prelude_ctx, mut prelude_fn_info) = prelude();
|
||||||
|
let prelude_ctx = Box::leak(Box::new(prelude_ctx));
|
||||||
|
|
||||||
let mut v6or = Validator::new(&parsed.0, parsed.1, "script", src, &prelude_ctx);
|
let mut v6or = Validator::new(&parsed.0, parsed.1, "script", src, prelude_ctx);
|
||||||
|
|
||||||
v6or.validate();
|
v6or.validate();
|
||||||
|
|
||||||
|
@ -196,10 +199,13 @@ pub fn run(src: &'static str) {
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let src = "
|
let src = "
|
||||||
loop (100000, 1) with {
|
fn sum_to {
|
||||||
|
(n) -> sum_to (n, 0)
|
||||||
(1, acc) -> acc
|
(1, acc) -> acc
|
||||||
(n, acc) -> recur (dec (n), add (n, acc))
|
(n, acc) -> sum_to (dec (n), add (n, acc))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sum_to (10000)
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
// struct_scalpel::print_dissection_info::<value::Value>()
|
// struct_scalpel::print_dissection_info::<value::Value>()
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub struct Process<'src> {
|
||||||
pub input: &'static str,
|
pub input: &'static str,
|
||||||
pub src: &'static str,
|
pub src: &'static str,
|
||||||
pub locals: Vec<(String, Value<'src>)>,
|
pub locals: Vec<(String, Value<'src>)>,
|
||||||
pub prelude: Vec<(String, Value<'src>)>,
|
pub prelude: &'src Vec<(String, Value<'src>)>,
|
||||||
pub ast: &'src Ast,
|
pub ast: &'src Ast,
|
||||||
pub span: SimpleSpan,
|
pub span: SimpleSpan,
|
||||||
pub fn_info: std::collections::HashMap<*const Ast, FnInfo>,
|
pub fn_info: std::collections::HashMap<*const Ast, FnInfo>,
|
||||||
|
@ -296,25 +296,28 @@ impl<'src> Process<'src> {
|
||||||
// can't just use the `caller` value b/c borrow checker nonsense
|
// can't just use the `caller` value b/c borrow checker nonsense
|
||||||
let args = Tuple(args);
|
let args = Tuple(args);
|
||||||
let to = self.locals.len();
|
let to = self.locals.len();
|
||||||
let mut f = f.borrow_mut();
|
if !f.has_run {
|
||||||
for i in 0..f.enclosing.len() {
|
for i in 0..f.enclosing.len() {
|
||||||
let (name, value) = f.enclosing[i].clone();
|
let (name, value) = f.enclosing[i].clone();
|
||||||
if !f.has_run && matches!(value, Value::FnDecl(_)) {
|
if !f.has_run && matches!(value, Value::FnDecl(_)) {
|
||||||
let defined = self.resolve(&name);
|
let defined = self.resolve(&name);
|
||||||
match defined {
|
match defined {
|
||||||
Ok(Value::Fn(defined)) => f.enclosing[i] = (name.clone(), Fn(defined)),
|
Ok(Value::Fn(defined)) => {
|
||||||
Ok(Value::FnDecl(_)) => {
|
f.enclosing[i] = (name.clone(), Fn(defined))
|
||||||
return self.panic(format!(
|
}
|
||||||
"function `{name}` called before it was defined"
|
Ok(Value::FnDecl(_)) => {
|
||||||
))
|
return self.panic(format!(
|
||||||
}
|
"function `{name}` called before it was defined"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.locals.push(f.enclosing[i].clone());
|
||||||
}
|
}
|
||||||
self.locals.push(f.enclosing[i].clone());
|
f.has_run = true;
|
||||||
}
|
}
|
||||||
f.has_run = true;
|
|
||||||
let input = self.input;
|
let input = self.input;
|
||||||
let src = self.src;
|
let src = self.src;
|
||||||
self.input = f.input;
|
self.input = f.input;
|
||||||
|
|
226
src/validator.rs
226
src/validator.rs
|
@ -1,5 +1,5 @@
|
||||||
use crate::parser::*;
|
use crate::parser::*;
|
||||||
use crate::spans::Span;
|
use crate::spans::{Span, Spanned};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ fn match_arities(arities: &HashSet<Arity>, num_args: u8) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Validator<'a, 'src> {
|
pub struct Validator<'a> {
|
||||||
pub locals: Vec<(String, Span, FnInfo)>,
|
pub locals: Vec<(String, Span, FnInfo)>,
|
||||||
pub prelude: &'a Vec<(String, Value<'src>)>,
|
pub prelude: &'a Vec<(String, Value<'a>)>,
|
||||||
pub input: &'static str,
|
pub input: &'static str,
|
||||||
pub src: &'static str,
|
pub src: &'static str,
|
||||||
pub ast: &'a Ast,
|
pub ast: &'a Ast,
|
||||||
|
@ -65,14 +65,14 @@ pub struct Validator<'a, 'src> {
|
||||||
status: VStatus,
|
status: VStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'src: 'a> Validator<'a, 'src> {
|
impl<'a> Validator<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ast: &'a Ast,
|
ast: &'a Ast,
|
||||||
span: Span,
|
span: Span,
|
||||||
input: &'static str,
|
input: &'static str,
|
||||||
src: &'static str,
|
src: &'static str,
|
||||||
prelude: &'a Vec<(String, Value<'src>)>,
|
prelude: &'a Vec<(String, Value<'a>)>,
|
||||||
) -> Validator<'a, 'src> {
|
) -> Validator<'a> {
|
||||||
Validator {
|
Validator {
|
||||||
input,
|
input,
|
||||||
src,
|
src,
|
||||||
|
@ -109,7 +109,7 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
|
|
||||||
fn resolved(&self, name: &str) -> bool {
|
fn resolved(&self, name: &str) -> bool {
|
||||||
self.locals.iter().any(|(bound, ..)| name == bound.as_str())
|
self.locals.iter().any(|(bound, ..)| name == bound.as_str())
|
||||||
|| self.prelude.iter().any(|(bound, _)| name == bound.as_str())
|
|| self.prelude.iter().any(|(bound, _)| name == *bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bound(&self, name: &str) -> Option<&(String, Span, FnInfo)> {
|
fn bound(&self, name: &str) -> Option<&(String, Span, FnInfo)> {
|
||||||
|
@ -143,6 +143,13 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit(&mut self, node: &'a Spanned<Ast>) {
|
||||||
|
let (expr, span) = node;
|
||||||
|
self.ast = expr;
|
||||||
|
self.span = *span;
|
||||||
|
self.validate();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate(&mut self) {
|
pub fn validate(&mut self) {
|
||||||
use Ast::*;
|
use Ast::*;
|
||||||
let root = self.ast;
|
let root = self.ast;
|
||||||
|
@ -179,18 +186,13 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
}
|
}
|
||||||
let to = self.locals.len();
|
let to = self.locals.len();
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
for (expr, span) in block.iter().take(block.len() - 1) {
|
for line in block.iter().take(block.len() - 1) {
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
self.ast = expr;
|
self.visit(line);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (expr, span) = block.last().unwrap();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
self.validate();
|
self.visit(block.last().unwrap());
|
||||||
|
|
||||||
let block_bindings = self.locals.split_off(to);
|
let block_bindings = self.locals.split_off(to);
|
||||||
|
|
||||||
|
@ -207,22 +209,12 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
|
|
||||||
let (expr, span) = cond.as_ref();
|
self.visit(cond.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
// pass through tailpos only to then/else
|
// pass through tailpos only to then/else
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
let (expr, span) = then.as_ref();
|
self.visit(then.as_ref());
|
||||||
self.ast = expr;
|
self.visit(r#else.as_ref());
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
let (expr, span) = r#else.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
Tuple(members) => {
|
Tuple(members) => {
|
||||||
if members.is_empty() {
|
if members.is_empty() {
|
||||||
|
@ -230,10 +222,8 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for (expr, span) in members {
|
for member in members {
|
||||||
self.ast = expr;
|
self.visit(member);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
|
@ -244,10 +234,8 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for (expr, span) in args {
|
for arg in args {
|
||||||
self.ast = expr;
|
self.visit(arg);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
self.status.has_placeholder = false;
|
self.status.has_placeholder = false;
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
|
@ -267,30 +255,21 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for (expr, span) in list {
|
for member in list {
|
||||||
self.ast = expr;
|
self.visit(member);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
Pair(_, value) => {
|
Pair(_, value) => self.visit(value.as_ref()),
|
||||||
let (expr, span) = value.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
|
||||||
Dict(dict) => {
|
Dict(dict) => {
|
||||||
if dict.is_empty() {
|
if dict.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for (expr, span) in dict {
|
for pair in dict {
|
||||||
self.ast = expr;
|
self.visit(pair)
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
|
@ -299,31 +278,16 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
// check arity against fn info if first term is word and second term is args
|
// check arity against fn info if first term is word and second term is args
|
||||||
Synthetic(first, second, rest) => {
|
Synthetic(first, second, rest) => {
|
||||||
match (&first.0, &second.0) {
|
match (&first.0, &second.0) {
|
||||||
(Ast::Word(_), Ast::Keyword(_)) => {
|
(Ast::Word(_), Ast::Keyword(_)) => self.visit(first.as_ref()),
|
||||||
let (expr, span) = first.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
|
||||||
(Ast::Keyword(_), Ast::Arguments(args)) => {
|
(Ast::Keyword(_), Ast::Arguments(args)) => {
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
self.err("called keywords may only take one argument".to_string())
|
self.err("called keywords may only take one argument".to_string())
|
||||||
}
|
}
|
||||||
let (expr, span) = second.as_ref();
|
self.visit(second.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
(Ast::Word(name), Ast::Arguments(args)) => {
|
(Ast::Word(name), Ast::Arguments(args)) => {
|
||||||
let (expr, span) = first.as_ref();
|
self.visit(first.as_ref());
|
||||||
self.ast = expr;
|
self.visit(second.as_ref());
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
let (expr, span) = second.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
//TODO: check arities of prelude fns, too
|
//TODO: check arities of prelude fns, too
|
||||||
let fn_binding = self.bound(name);
|
let fn_binding = self.bound(name);
|
||||||
|
@ -337,32 +301,20 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
for term in rest {
|
for term in rest {
|
||||||
let (expr, span) = term;
|
self.visit(term);
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WhenClause(cond, body) => {
|
WhenClause(cond, body) => {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
let (expr, span) = cond.as_ref();
|
self.visit(cond.as_ref());
|
||||||
self.ast = expr;
|
//pass through tail position for when bodies
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
let (expr, span) = body.as_ref();
|
self.visit(body.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
When(clauses) => {
|
When(clauses) => {
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
let (expr, span) = clause;
|
self.visit(clause);
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,54 +326,30 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
} else {
|
} else {
|
||||||
self.bind(name.to_string());
|
self.bind(name.to_string());
|
||||||
}
|
}
|
||||||
let (expr, span) = boxed.as_ref();
|
self.visit(boxed.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
Let(lhs, rhs) => {
|
Let(lhs, rhs) => {
|
||||||
let (expr, span) = rhs.as_ref();
|
self.visit(rhs.as_ref());
|
||||||
self.ast = expr;
|
self.visit(lhs.as_ref());
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
let (expr, span) = lhs.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
MatchClause(pattern, guard, body) => {
|
MatchClause(pattern, guard, body) => {
|
||||||
let to = self.locals.len();
|
let to = self.locals.len();
|
||||||
|
|
||||||
let (patt, span) = pattern.as_ref();
|
self.visit(pattern.as_ref());
|
||||||
self.ast = patt;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
if let Some((expr, span)) = guard.as_ref() {
|
if let Some(guard) = guard.as_ref() {
|
||||||
self.ast = expr;
|
self.visit(guard);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (expr, span) = body.as_ref();
|
self.visit(body.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
self.locals.truncate(to);
|
self.locals.truncate(to);
|
||||||
}
|
}
|
||||||
Match(scrutinee, clauses) => {
|
Match(scrutinee, clauses) => {
|
||||||
let (expr, span) = scrutinee.as_ref();
|
self.visit(scrutinee.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
for clause in clauses {
|
for clause in clauses {
|
||||||
let (expr, span) = clause;
|
self.visit(clause);
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnDeclaration(name) => {
|
FnDeclaration(name) => {
|
||||||
|
@ -488,10 +416,7 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
Panic(msg) => {
|
Panic(msg) => {
|
||||||
let tailpos = self.status.tail_position;
|
let tailpos = self.status.tail_position;
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
let (expr, span) = msg.as_ref();
|
self.visit(msg.as_ref());
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
self.status.tail_position = tailpos;
|
self.status.tail_position = tailpos;
|
||||||
}
|
}
|
||||||
// TODO: fix the tail call here?
|
// TODO: fix the tail call here?
|
||||||
|
@ -500,39 +425,23 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
return self.err("do expressions must have at least two terms".to_string());
|
return self.err("do expressions must have at least two terms".to_string());
|
||||||
}
|
}
|
||||||
for term in terms.iter().take(terms.len() - 1) {
|
for term in terms.iter().take(terms.len() - 1) {
|
||||||
let (expr, span) = term;
|
self.visit(term);
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
|
let last = terms.last().unwrap();
|
||||||
let (expr, span) = terms.last().unwrap();
|
self.visit(last);
|
||||||
self.ast = expr;
|
if matches!(last.0, Ast::Recur(_)) {
|
||||||
self.span = *span;
|
|
||||||
if matches!(expr, Ast::Recur(_)) {
|
|
||||||
self.err("`recur` may not be used in `do` forms".to_string());
|
self.err("`recur` may not be used in `do` forms".to_string());
|
||||||
}
|
}
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
Repeat(times, body) => {
|
Repeat(times, body) => {
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
let (expr, span) = times.as_ref();
|
self.visit(times.as_ref());
|
||||||
self.ast = expr;
|
self.visit(body.as_ref());
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
let (expr, span) = body.as_ref();
|
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
Loop(with, body) => {
|
Loop(with, body) => {
|
||||||
let (expr, span) = with.as_ref();
|
self.visit(with.as_ref());
|
||||||
self.span = *span;
|
|
||||||
self.ast = expr;
|
|
||||||
self.validate();
|
|
||||||
|
|
||||||
let Ast::Tuple(input) = expr else {
|
let Ast::Tuple(input) = &with.0 else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -588,10 +497,7 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
|
|
||||||
self.status.tail_position = false;
|
self.status.tail_position = false;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
let (expr, span) = arg;
|
self.visit(arg);
|
||||||
self.ast = expr;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WordPattern(name) => match self.bound(name) {
|
WordPattern(name) => match self.bound(name) {
|
||||||
|
@ -654,25 +560,15 @@ impl<'a, 'src: 'a> Validator<'a, 'src> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for term in terms.iter().take(terms.len() - 1) {
|
for term in terms.iter().take(terms.len() - 1) {
|
||||||
let (patt, span) = term;
|
self.visit(term);
|
||||||
self.ast = patt;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status.last_term = true;
|
self.status.last_term = true;
|
||||||
let (patt, span) = terms.last().unwrap();
|
let last = terms.last().unwrap();
|
||||||
self.ast = patt;
|
self.visit(last);
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
self.status.last_term = false;
|
self.status.last_term = false;
|
||||||
}
|
}
|
||||||
PairPattern(_, patt) => {
|
PairPattern(_, patt) => self.visit(patt.as_ref()),
|
||||||
let (patt, span) = patt.as_ref();
|
|
||||||
self.ast = patt;
|
|
||||||
self.span = *span;
|
|
||||||
self.validate();
|
|
||||||
}
|
|
||||||
// terminals can never be invalid
|
// terminals can never be invalid
|
||||||
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) => (),
|
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) => (),
|
||||||
// terminal patterns can never be invalid
|
// terminal patterns can never be invalid
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub enum Value<'src> {
|
||||||
List(Vector<Self>),
|
List(Vector<Self>),
|
||||||
Dict(HashMap<&'static str, Self>),
|
Dict(HashMap<&'static str, Self>),
|
||||||
Box(&'static str, Rc<RefCell<Self>>),
|
Box(&'static str, Rc<RefCell<Self>>),
|
||||||
Fn(Rc<RefCell<Fn<'src>>>),
|
Fn(Rc<Fn<'src>>),
|
||||||
FnDecl(&'static str),
|
FnDecl(&'static str),
|
||||||
Base(BaseFn<'src>),
|
Base(BaseFn<'src>),
|
||||||
Recur(Vec<Self>),
|
Recur(Vec<Self>),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user