forked from Orchid/orchid
Mainly worked on the rule matcher
Also fixed the name collector, and lambda parameters are no longer resolved at parsing to support planned macro-based pattern matching. The rule matcher clones a lot, the number of clones could be zero.
This commit is contained in:
@@ -29,7 +29,7 @@ where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone {
|
||||
.then_ignore(enum_parser!(Lexeme::Comment).repeated())
|
||||
.then(expr.repeated().at_least(1))
|
||||
.map(|((name, typ), mut body): ((String, Vec<Expr>), Vec<Expr>)| {
|
||||
for ent in &mut body { ent.bind_parameter(&name) };
|
||||
// for ent in &mut body { ent.bind_parameter(&name) };
|
||||
Clause::Lambda(name, typ, body)
|
||||
})
|
||||
}
|
||||
@@ -54,9 +54,9 @@ where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone {
|
||||
.try_map(|((name, typ), mut body), s| if name == None && typ.is_empty() {
|
||||
Err(Simple::custom(s, "Auto without name or type has no effect"))
|
||||
} else {
|
||||
if let Some(n) = &name {
|
||||
for ent in &mut body { ent.bind_parameter(n) }
|
||||
}
|
||||
// if let Some(n) = &name {
|
||||
// for ent in &mut body { ent.bind_parameter(n) }
|
||||
// }
|
||||
Ok(Clause::Auto(name, typ, body))
|
||||
})
|
||||
}
|
||||
@@ -69,6 +69,13 @@ fn name_parser() -> impl Parser<Lexeme, Vec<String>, Error = Simple<Lexeme>> + C
|
||||
).at_least(1)
|
||||
}
|
||||
|
||||
fn placeholder_parser() -> impl Parser<Lexeme, String, Error = Simple<Lexeme>> + Clone {
|
||||
enum_parser!(Lexeme::Name).try_map(|name, span| {
|
||||
name.strip_prefix("$").map(&str::to_string)
|
||||
.ok_or(Simple::custom(span, "Not a placeholder"))
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse an expression without a type annotation
|
||||
pub fn xpr_parser() -> impl Parser<Lexeme, Expr, Error = Simple<Lexeme>> {
|
||||
recursive(|expr| {
|
||||
@@ -76,7 +83,19 @@ pub fn xpr_parser() -> impl Parser<Lexeme, Expr, Error = Simple<Lexeme>> {
|
||||
enum_parser!(Lexeme::Comment).repeated()
|
||||
.ignore_then(choice((
|
||||
enum_parser!(Lexeme >> Literal; Int, Num, Char, Str).map(Clause::Literal),
|
||||
name_parser().map(Clause::Name),
|
||||
placeholder_parser().map(|n| Clause::Placeh(n, None)),
|
||||
just(Lexeme::name("..."))
|
||||
.ignore_then(placeholder_parser())
|
||||
.then(
|
||||
just(Lexeme::Type)
|
||||
.ignore_then(enum_parser!(Lexeme::Int))
|
||||
.or_not().map(Option::unwrap_or_default)
|
||||
)
|
||||
.map(|(name, prio)| Clause::Placeh(name, Some(prio.try_into().unwrap()))),
|
||||
name_parser().map(|qualified| Clause::Name {
|
||||
local: if qualified.len() == 1 {Some(qualified[0].clone())} else {None},
|
||||
qualified
|
||||
}),
|
||||
sexpr_parser(expr.clone()),
|
||||
lambda_parser(expr.clone()),
|
||||
auto_parser(expr.clone())
|
||||
|
||||
@@ -29,7 +29,7 @@ fn op_parser<'a, T: AsRef<str> + Clone>(ops: &[T]) -> BoxedParser<'a, char, Stri
|
||||
/// TODO: `.` could possibly be parsed as an operator depending on context. This operator is very
|
||||
/// common in maths so it's worth a try. Investigate.
|
||||
pub fn modname_parser<'a>() -> impl Parser<char, String, Error = Simple<char>> + 'a {
|
||||
let not_name_char: Vec<char> = vec![':', '\\', '@', '"', '\'', '(', ')', ','];
|
||||
let not_name_char: Vec<char> = vec![':', '\\', '@', '"', '\'', '(', ')', ',', '.'];
|
||||
filter(move |c| !not_name_char.contains(c) && !c.is_whitespace())
|
||||
.repeated().at_least(1)
|
||||
.collect()
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::collections::HashSet;
|
||||
use std::iter;
|
||||
|
||||
use crate::{enum_parser, expression::{Expr, Clause, Rule}};
|
||||
use crate::enum_parser;
|
||||
use crate::expression::{Expr, Clause, Rule};
|
||||
use crate::utils::BoxedIter;
|
||||
use crate::utils::Stackframe;
|
||||
|
||||
use super::expression::xpr_parser;
|
||||
use super::import;
|
||||
@@ -19,32 +21,74 @@ pub enum FileEntry {
|
||||
Rule(Rule, bool)
|
||||
}
|
||||
|
||||
fn visit_all_names_clause_recur<'a, F>(
|
||||
clause: &'a Clause,
|
||||
binds: Stackframe<String>,
|
||||
mut cb: &mut F
|
||||
) where F: FnMut(&'a Vec<String>) {
|
||||
match clause {
|
||||
Clause::Auto(name, typ, body) => {
|
||||
for x in typ.iter() {
|
||||
visit_all_names_expr_recur(x, binds.clone(), &mut cb)
|
||||
}
|
||||
let binds_dup = binds.clone();
|
||||
let new_binds = if let Some(n) = name {
|
||||
binds_dup.push(n.to_owned())
|
||||
} else {
|
||||
binds
|
||||
};
|
||||
for x in body.iter() {
|
||||
visit_all_names_expr_recur(x, new_binds.clone(), &mut cb)
|
||||
}
|
||||
},
|
||||
Clause::Lambda(name, typ, body) => {
|
||||
for x in typ.iter() {
|
||||
visit_all_names_expr_recur(x, binds.clone(), &mut cb)
|
||||
}
|
||||
for x in body.iter() {
|
||||
visit_all_names_expr_recur(x, binds.push(name.to_owned()), &mut cb)
|
||||
}
|
||||
},
|
||||
Clause::S(_, body) => for x in body.iter() {
|
||||
visit_all_names_expr_recur(x, binds.clone(), &mut cb)
|
||||
},
|
||||
Clause::Name{ local, qualified } => {
|
||||
if let Some(name) = local {
|
||||
if binds.iter().all(|x| x != name) {
|
||||
cb(qualified)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively iterate through all "names" in an expression. It also finds a lot of things that
|
||||
/// aren't names, such as all bound parameters. Generally speaking, this is not a very
|
||||
/// sophisticated search.
|
||||
///
|
||||
/// TODO: find a way to exclude parameters
|
||||
fn find_all_names_recur<'a>(expr: &'a Expr) -> BoxedIter<&'a Vec<String>> {
|
||||
let proc_clause = |clause: &'a Clause| match clause {
|
||||
Clause::Auto(_, typ, body) | Clause::Lambda(_, typ, body) => Box::new(
|
||||
typ.iter().flat_map(find_all_names_recur)
|
||||
.chain(body.iter().flat_map(find_all_names_recur))
|
||||
) as BoxedIter<&'a Vec<String>>,
|
||||
Clause::S(_, body) => Box::new(
|
||||
body.iter().flat_map(find_all_names_recur)
|
||||
),
|
||||
Clause::Name(x) => Box::new(iter::once(x)),
|
||||
_ => Box::new(iter::empty())
|
||||
};
|
||||
fn visit_all_names_expr_recur<'a, F>(
|
||||
expr: &'a Expr,
|
||||
binds: Stackframe<String>,
|
||||
cb: &mut F
|
||||
) where F: FnMut(&'a Vec<String>) {
|
||||
let Expr(val, typ) = expr;
|
||||
visit_all_names_clause_recur(val, binds.clone(), cb);
|
||||
if let Some(t) = typ {
|
||||
Box::new(proc_clause(val).chain(find_all_names_recur(t)))
|
||||
} else { proc_clause(val) }
|
||||
visit_all_names_expr_recur(t, binds, cb)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all names that occur in an expression
|
||||
fn find_all_names(expr: &Expr) -> HashSet<&Vec<String>> {
|
||||
find_all_names_recur(expr).collect()
|
||||
let mut ret = HashSet::new();
|
||||
visit_all_names_expr_recur(expr, Stackframe::new(String::new()), &mut |n| {
|
||||
if !n.last().unwrap().starts_with("$") {
|
||||
ret.insert(n);
|
||||
}
|
||||
});
|
||||
ret
|
||||
}
|
||||
|
||||
fn rule_parser() -> impl Parser<Lexeme, (Vec<Expr>, NotNan<f64>, Vec<Expr>), Error = Simple<Lexeme>> {
|
||||
|
||||
Reference in New Issue
Block a user