Use chumsky::recursive::Recursive in place of fn recursive
This commit is contained in:
parent
1b9f1d56bc
commit
e4f70dde42
730
src/main.rs
730
src/main.rs
|
@ -9,8 +9,8 @@
|
|||
// * ignored words
|
||||
|
||||
// todo:
|
||||
// * [ ] rewrite fn parser to use chumsky::Recursive::declare/define
|
||||
// - [ ] do this to extract/simplify/DRY things like tuple patterns, fn clauses, etc.
|
||||
// * [x] rewrite fn parser to use chumsky::Recursive::declare/define
|
||||
// - [x] do this to extract/simplify/DRY things like tuple patterns, fn clauses, etc.
|
||||
// * [x] Work around chumsky::Stream::from_iter().spanned disappearing in most recent version
|
||||
// * [x] investigate using labels (which is behind a compiler flag, somehow)
|
||||
// * [ ] wire up Ariadne parsing errors
|
||||
|
@ -28,6 +28,7 @@
|
|||
use chumsky::{
|
||||
input::{Stream, ValueInput},
|
||||
prelude::*,
|
||||
recursive::Recursive,
|
||||
};
|
||||
use imbl::{HashMap, Vector};
|
||||
use std::fmt;
|
||||
|
@ -344,415 +345,400 @@ fn parser<'src, I>(
|
|||
where
|
||||
I: ValueInput<'src, Token = Token<'src>, Span = Span>,
|
||||
{
|
||||
recursive(|expr| {
|
||||
let separators = recursive(|separators| {
|
||||
just(Token::Punctuation(","))
|
||||
.or(just(Token::Punctuation("\n")))
|
||||
.then(separators.clone().repeated())
|
||||
let mut expr = Recursive::declare();
|
||||
|
||||
let mut pattern = Recursive::declare();
|
||||
|
||||
let mut simple = Recursive::declare();
|
||||
|
||||
let mut nonbinding = Recursive::declare();
|
||||
|
||||
let separators = recursive(|separators| {
|
||||
just(Token::Punctuation(","))
|
||||
.or(just(Token::Punctuation("\n")))
|
||||
.then(separators.clone().repeated())
|
||||
});
|
||||
|
||||
let terminators = recursive(|terminators| {
|
||||
just(Token::Punctuation(";"))
|
||||
.or(just(Token::Punctuation("\n")))
|
||||
.then(terminators.clone().repeated())
|
||||
});
|
||||
|
||||
let placeholder_pattern =
|
||||
select! {Token::Punctuation("_") => Pattern::Placeholder}.map_with(|p, e| (p, e.span()));
|
||||
|
||||
let word_pattern =
|
||||
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)),
|
||||
}
|
||||
.map_with(|a, e| (a, e.span()));
|
||||
|
||||
let tuple_pattern = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Pattern::Tuple(tuple), e.span()))
|
||||
.labelled("tuple pattern");
|
||||
|
||||
let list_pattern = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.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)}
|
||||
.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()))),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let dict_pattern = pair_pattern
|
||||
.or(shorthand_pattern)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Punctuation("#{")),
|
||||
just(Token::Punctuation("}")),
|
||||
)
|
||||
.map_with(|dict, e| (Pattern::Dict(dict), e.span()));
|
||||
|
||||
pattern.define(
|
||||
atom_pattern
|
||||
.or(word_pattern)
|
||||
.or(placeholder_pattern)
|
||||
.or(tuple_pattern.clone())
|
||||
.or(list_pattern)
|
||||
.or(dict_pattern)
|
||||
.labelled("pattern"),
|
||||
);
|
||||
|
||||
let placeholder =
|
||||
select! {Token::Punctuation("_") => Ast::Placeholder}.map_with(|p, e| (p, e.span()));
|
||||
|
||||
let word = select! { Token::Word(w) => Ast::Word(w) }
|
||||
.map_with(|w, e| (w, e.span()))
|
||||
.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)),
|
||||
}
|
||||
.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 tuple = simple
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Ast::Tuple(tuple), e.span()));
|
||||
|
||||
let args = simple
|
||||
.clone()
|
||||
.or(placeholder)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|args, e| (Ast::Arguments(args), e.span()));
|
||||
|
||||
let synth_root = word.clone().or(keyword.clone());
|
||||
|
||||
let synth_term = keyword.clone().or(args);
|
||||
|
||||
let synthetic = synth_root
|
||||
.then(synth_term.clone())
|
||||
.then(synth_term.clone().repeated().collect())
|
||||
.map_with(|((root, first), rest), e| {
|
||||
(
|
||||
Ast::Synthetic(Box::new(root), Box::new(first), rest),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let pattern = recursive(|pattern| {
|
||||
let placeholder = select! {Token::Punctuation("_") => Pattern::Placeholder}
|
||||
.map_with(|p, e| (p, e.span()));
|
||||
let list = simple
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
||||
.map_with(|list, e| (Ast::List(list), e.span()));
|
||||
|
||||
let word =
|
||||
select! { Token::Word(w) => Pattern::Word(w) }.map_with(|w, e| (w, e.span()));
|
||||
let pair = select! {Token::Keyword(k) => Value::Keyword(k)}
|
||||
.then(simple.clone())
|
||||
.map_with(|(kw, expr), e| (Ast::Pair(kw, Box::new(expr)), e.span()));
|
||||
|
||||
let atom = 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)),
|
||||
}
|
||||
.map_with(|a, e| (a, 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 tuple = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Pattern::Tuple(tuple), e.span()));
|
||||
let dict = pair
|
||||
.or(shorthand)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Punctuation("#{")),
|
||||
just(Token::Punctuation("}")),
|
||||
)
|
||||
.map_with(|dict, e| (Ast::Dict(dict), e.span()));
|
||||
|
||||
let list = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
||||
.map_with(|list, e| (Pattern::List(list), e.span()));
|
||||
simple.define(
|
||||
synthetic
|
||||
.or(word)
|
||||
.or(keyword)
|
||||
.or(value)
|
||||
.or(tuple)
|
||||
.or(list)
|
||||
.or(dict)
|
||||
.labelled("simple expression"),
|
||||
);
|
||||
|
||||
let pair = select! {Token::Keyword(k) => Value::Keyword(k)}
|
||||
.then(pattern.clone())
|
||||
.map_with(|(kw, patt), e| (Pattern::Pair(kw, Box::new(patt)), e.span()));
|
||||
let block = expr
|
||||
.clone()
|
||||
.separated_by(terminators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
|
||||
.map_with(|block, e| (Ast::Block(block), e.span()))
|
||||
.recover_with(via_parser(nested_delimiters(
|
||||
Token::Punctuation("{"),
|
||||
Token::Punctuation("}"),
|
||||
[
|
||||
(Token::Punctuation("("), Token::Punctuation(")")),
|
||||
(Token::Punctuation("["), Token::Punctuation("]")),
|
||||
],
|
||||
|span| (Ast::Error, span),
|
||||
)));
|
||||
|
||||
let shorthand = select! {Token::Word(w) => w}.map_with(|w, e| {
|
||||
(
|
||||
Pattern::Pair(Value::Keyword(w), Box::new((Pattern::Word(w), e.span()))),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let dict = pair
|
||||
.or(shorthand)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Punctuation("#{")),
|
||||
just(Token::Punctuation("}")),
|
||||
)
|
||||
.map_with(|dict, e| (Pattern::Dict(dict), e.span()));
|
||||
|
||||
atom.or(word)
|
||||
.or(placeholder)
|
||||
.or(tuple)
|
||||
.or(list)
|
||||
.or(dict)
|
||||
.labelled("pattern")
|
||||
let if_ = just(Token::Reserved("if"))
|
||||
.ignore_then(simple.clone())
|
||||
.then_ignore(just(Token::Reserved("then")))
|
||||
.then(expr.clone())
|
||||
.then_ignore(just(Token::Reserved("else")))
|
||||
.then(expr.clone())
|
||||
.map_with(|((condition, then_branch), else_branch), e| {
|
||||
(
|
||||
Ast::If(
|
||||
Box::new(condition),
|
||||
Box::new(then_branch),
|
||||
Box::new(else_branch),
|
||||
),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let placeholder =
|
||||
select! {Token::Punctuation("_") => Ast::Placeholder}.map_with(|p, e| (p, e.span()));
|
||||
let when_clause = simple
|
||||
.clone()
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(expr.clone())
|
||||
.map_with(|(cond, body), e| (Ast::WhenClause(Box::new(cond), Box::new(body)), e.span()));
|
||||
|
||||
let word = select! { Token::Word(w) => Ast::Word(w) }
|
||||
.map_with(|w, e| (w, e.span()))
|
||||
.labelled("word");
|
||||
|
||||
let simple = recursive(|simple| {
|
||||
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)),
|
||||
}
|
||||
.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 word = select! {Token::Word(w) => Ast::Word(w)}.map_with(|w, e| (w, e.span()));
|
||||
|
||||
let tuple = simple
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
let when = just(Token::Reserved("when"))
|
||||
.ignore_then(
|
||||
when_clause
|
||||
.separated_by(terminators.clone())
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Ast::Tuple(tuple), e.span()));
|
||||
|
||||
// let placeholder = select! {Token::Punctuation("_") => Ast::Placeholder}
|
||||
// .map_with(|p, e| (p, e.span()));
|
||||
|
||||
let args = simple
|
||||
.clone()
|
||||
.or(placeholder)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|args, e| (Ast::Arguments(args), e.span()));
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
)
|
||||
.map_with(|clauses, e| (Ast::When(clauses), e.span()));
|
||||
|
||||
let synth_root = word.clone().or(keyword.clone());
|
||||
let match_clause = pattern
|
||||
.clone()
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(expr.clone())
|
||||
.map_with(|(patt, body), e| (Ast::MatchClause(Box::new(patt), Box::new(body)), e.span()));
|
||||
|
||||
let synth_term = keyword.clone().or(args);
|
||||
|
||||
let synthetic = synth_root
|
||||
.then(synth_term.clone())
|
||||
.then(synth_term.clone().repeated().collect())
|
||||
.map_with(|((root, first), rest), e| {
|
||||
(
|
||||
Ast::Synthetic(Box::new(root), Box::new(first), rest),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
|
||||
let list = simple
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.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)}
|
||||
.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 dict = pair
|
||||
.or(shorthand)
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Punctuation("#{")),
|
||||
just(Token::Punctuation("}")),
|
||||
)
|
||||
.map_with(|dict, e| (Ast::Dict(dict), e.span()));
|
||||
|
||||
synthetic
|
||||
.or(word)
|
||||
.or(keyword)
|
||||
.or(value)
|
||||
.or(tuple)
|
||||
.or(list)
|
||||
.or(dict)
|
||||
.labelled("simple expression")
|
||||
});
|
||||
|
||||
let terminators = recursive(|terminators| {
|
||||
just(Token::Punctuation("\n"))
|
||||
.or(just(Token::Punctuation(";")))
|
||||
.then(terminators.clone().repeated())
|
||||
.labelled("terminator")
|
||||
});
|
||||
|
||||
let nonbinding = recursive(|nonbinding| {
|
||||
let block = expr
|
||||
let match_ = just(Token::Reserved("match"))
|
||||
.ignore_then(simple.clone())
|
||||
.then_ignore(just(Token::Reserved("with")))
|
||||
.then(
|
||||
match_clause
|
||||
.clone()
|
||||
.separated_by(terminators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
|
||||
.map_with(|block, e| (Ast::Block(block), e.span()))
|
||||
.recover_with(via_parser(nested_delimiters(
|
||||
Token::Punctuation("{"),
|
||||
Token::Punctuation("}"),
|
||||
[
|
||||
(Token::Punctuation("("), Token::Punctuation(")")),
|
||||
(Token::Punctuation("["), Token::Punctuation("]")),
|
||||
],
|
||||
|span| (Ast::Error, span),
|
||||
)));
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
)
|
||||
.map_with(|(expr, clauses), e| (Ast::Match(Box::new(expr), clauses), e.span()));
|
||||
|
||||
let if_ = just(Token::Reserved("if"))
|
||||
.ignore_then(simple.clone())
|
||||
.then_ignore(just(Token::Reserved("then")))
|
||||
.then(expr.clone())
|
||||
.then_ignore(just(Token::Reserved("else")))
|
||||
.then(expr.clone())
|
||||
.map_with(|((condition, then_branch), else_branch), e| {
|
||||
(
|
||||
Ast::If(
|
||||
Box::new(condition),
|
||||
Box::new(then_branch),
|
||||
Box::new(else_branch),
|
||||
),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
let conditional = when.or(if_).or(match_);
|
||||
|
||||
let when_clause = simple
|
||||
//todo:
|
||||
// * [x] do
|
||||
// * [ ] loop
|
||||
// * [ ] repeat
|
||||
// * [x] panic!
|
||||
|
||||
let panic = just(Token::Reserved("panic!"))
|
||||
.ignore_then(nonbinding.clone())
|
||||
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span()));
|
||||
|
||||
let do_ = just(Token::Reserved("do"))
|
||||
.ignore_then(
|
||||
nonbinding
|
||||
.clone()
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(expr.clone())
|
||||
.map_with(|(cond, body), e| {
|
||||
(Ast::WhenClause(Box::new(cond), Box::new(body)), e.span())
|
||||
});
|
||||
|
||||
let when = just(Token::Reserved("when"))
|
||||
.ignore_then(
|
||||
when_clause
|
||||
.separated_by(terminators.clone())
|
||||
.allow_trailing()
|
||||
.allow_leading()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
.separated_by(
|
||||
just(Token::Punctuation(">")).then(just(Token::Punctuation("\n")).repeated()),
|
||||
)
|
||||
.map_with(|clauses, e| (Ast::When(clauses), e.span()));
|
||||
.collect(),
|
||||
)
|
||||
.map_with(|exprs, e| (Ast::Do(exprs), e.span()));
|
||||
|
||||
let match_clause = pattern
|
||||
let repeat = just(Token::Reserved("repeat"))
|
||||
.ignore_then(simple.clone())
|
||||
.then(block.clone())
|
||||
.map_with(|(count, body), e| (Ast::Repeat(Box::new(count), Box::new(body)), e.span()));
|
||||
|
||||
let fn_clause = tuple_pattern
|
||||
.clone()
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(pattern, body), e| (Ast::FnClause(Box::new(pattern), Box::new(body)), e.span()))
|
||||
.labelled("function clause");
|
||||
|
||||
let lambda = just(Token::Reserved("fn"))
|
||||
.ignore_then(fn_clause.clone())
|
||||
.map_with(|clause, e| (Ast::Fn("anonymous", vec![clause]), e.span()));
|
||||
|
||||
nonbinding.define(
|
||||
simple
|
||||
.clone()
|
||||
.or(conditional)
|
||||
.or(block)
|
||||
.or(lambda)
|
||||
.or(panic)
|
||||
.or(do_)
|
||||
.or(repeat)
|
||||
.labelled("nonbinding expression"),
|
||||
);
|
||||
|
||||
let let_ = just(Token::Reserved("let"))
|
||||
.ignore_then(pattern.clone())
|
||||
.then_ignore(just(Token::Punctuation("=")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(pattern, expression), e| {
|
||||
(Ast::Let(Box::new(pattern), Box::new(expression)), e.span())
|
||||
});
|
||||
|
||||
let box_ = just(Token::Reserved("box"))
|
||||
.ignore_then(word.clone())
|
||||
.then_ignore(just(Token::Punctuation("=")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(word, expr), e| {
|
||||
let name = if let Ast::Word(w) = word.0 {
|
||||
w
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Box(name, Box::new(expr)), e.span())
|
||||
});
|
||||
|
||||
let fn_decl = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.map_with(|(word, _), e| {
|
||||
let name = if let Ast::Word(w) = word {
|
||||
w
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::FnDeclaration(name), e.span())
|
||||
});
|
||||
|
||||
// let tuple_pattern = pattern
|
||||
// .clone()
|
||||
// .separated_by(separators.clone())
|
||||
// .allow_leading()
|
||||
// .allow_trailing()
|
||||
// .collect()
|
||||
// .delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
// .map_with(|tuple, e| (Pattern::Tuple(tuple), e.span()));
|
||||
|
||||
let fn_named = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.then(fn_clause.clone())
|
||||
.map_with(|(word, clause), e| {
|
||||
let name = if let Ast::Word(word) = word.0 {
|
||||
word
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Fn(name, vec![clause]), e.span())
|
||||
});
|
||||
|
||||
let fn_compound = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.then(
|
||||
fn_clause
|
||||
.clone()
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(expr.clone())
|
||||
.map_with(|(patt, body), e| {
|
||||
(Ast::MatchClause(Box::new(patt), Box::new(body)), e.span())
|
||||
});
|
||||
|
||||
let match_ = just(Token::Reserved("match"))
|
||||
.ignore_then(simple.clone())
|
||||
.then_ignore(just(Token::Reserved("with")))
|
||||
.then(
|
||||
match_clause
|
||||
.clone()
|
||||
.separated_by(terminators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
)
|
||||
.map_with(|(expr, clauses), e| (Ast::Match(Box::new(expr), clauses), e.span()));
|
||||
|
||||
let conditional = when.or(if_).or(match_);
|
||||
|
||||
//todo:
|
||||
// * [x] do
|
||||
// * [ ] loop
|
||||
// * [ ] repeat
|
||||
// * [x] panic!
|
||||
|
||||
let panic = just(Token::Reserved("panic!"))
|
||||
.ignore_then(nonbinding.clone())
|
||||
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span()));
|
||||
|
||||
let do_ = just(Token::Reserved("do"))
|
||||
.ignore_then(
|
||||
nonbinding
|
||||
.clone()
|
||||
.separated_by(
|
||||
just(Token::Punctuation(">"))
|
||||
.then(just(Token::Punctuation("\n")).repeated()),
|
||||
)
|
||||
.collect(),
|
||||
)
|
||||
.map_with(|exprs, e| (Ast::Do(exprs), e.span()));
|
||||
|
||||
let repeat = just(Token::Reserved("repeat"))
|
||||
.ignore_then(simple.clone())
|
||||
.then(block.clone())
|
||||
.map_with(|(count, body), e| {
|
||||
(Ast::Repeat(Box::new(count), Box::new(body)), e.span())
|
||||
});
|
||||
|
||||
let tuple_pattern = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.separated_by(terminators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Pattern::Tuple(tuple), e.span()))
|
||||
.labelled("tuple pattern");
|
||||
|
||||
let fn_clause = tuple_pattern
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(pattern, body), e| {
|
||||
(Ast::FnClause(Box::new(pattern), Box::new(body)), e.span())
|
||||
})
|
||||
.labelled("function clause");
|
||||
|
||||
let lambda = just(Token::Reserved("fn"))
|
||||
.ignore_then(fn_clause)
|
||||
.map_with(|clause, e| (Ast::Fn("anonymous", vec![clause]), e.span()));
|
||||
|
||||
let loop_ = just(Token::Reserved("loop"));
|
||||
|
||||
simple
|
||||
.clone()
|
||||
.or(conditional)
|
||||
.or(block)
|
||||
.or(lambda)
|
||||
.or(panic)
|
||||
.or(do_)
|
||||
.labelled("nonbinding expression")
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
)
|
||||
.map_with(|(word, clauses), e| {
|
||||
let name = if let Ast::Word(word) = word.0 {
|
||||
word
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Fn(name, clauses), e.span())
|
||||
});
|
||||
|
||||
let let_ = just(Token::Reserved("let"))
|
||||
.ignore_then(pattern.clone())
|
||||
.then_ignore(just(Token::Punctuation("=")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(pattern, expression), e| {
|
||||
(Ast::Let(Box::new(pattern), Box::new(expression)), e.span())
|
||||
});
|
||||
let fn_ = fn_named.or(fn_compound).or(fn_decl);
|
||||
|
||||
let box_ = just(Token::Reserved("box"))
|
||||
.ignore_then(word.clone())
|
||||
.then_ignore(just(Token::Punctuation("=")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(word, expr), e| {
|
||||
let name = if let Ast::Word(w) = word.0 {
|
||||
w
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Box(name, Box::new(expr)), e.span())
|
||||
});
|
||||
let binding = let_.or(box_).or(fn_);
|
||||
|
||||
let fn_decl = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.map_with(|(word, _), e| {
|
||||
let name = if let Ast::Word(w) = word {
|
||||
w
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::FnDeclaration(name), e.span())
|
||||
});
|
||||
expr.define(binding.or(nonbinding));
|
||||
|
||||
let tuple_pattern = pattern
|
||||
.clone()
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Pattern::Tuple(tuple), e.span()));
|
||||
let script = expr
|
||||
.separated_by(terminators.clone())
|
||||
.allow_trailing()
|
||||
.allow_leading()
|
||||
.collect()
|
||||
.map_with(|exprs, e| (Ast::Block(exprs), e.span()));
|
||||
|
||||
let fn_clause = tuple_pattern
|
||||
.then_ignore(just(Token::Punctuation("->")))
|
||||
.then(nonbinding.clone())
|
||||
.map_with(|(pattern, body), e| {
|
||||
(Ast::FnClause(Box::new(pattern), Box::new(body)), e.span())
|
||||
});
|
||||
|
||||
let fn_named = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.then(fn_clause.clone())
|
||||
.map_with(|(word, clause), e| {
|
||||
let name = if let Ast::Word(word) = word.0 {
|
||||
word
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Fn(name, vec![clause]), e.span())
|
||||
});
|
||||
|
||||
let fn_compound = just(Token::Reserved("fn"))
|
||||
.ignore_then(word.clone())
|
||||
.then(
|
||||
fn_clause
|
||||
.clone()
|
||||
.separated_by(terminators)
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||
)
|
||||
.map_with(|(word, clauses), e| {
|
||||
let name = if let Ast::Word(word) = word.0 {
|
||||
word
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
(Ast::Fn(name, clauses), e.span())
|
||||
});
|
||||
|
||||
let fn_ = fn_named.or(fn_compound).or(fn_decl);
|
||||
|
||||
let binding = let_.or(box_).or(fn_);
|
||||
|
||||
nonbinding.or(binding)
|
||||
})
|
||||
script
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let src = "let #{a, :b b} = foo";
|
||||
let src = "let #{a, :b b} = foo\na(b(c),d)";
|
||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||
if lex_errs.len() > 0 {
|
||||
println!("{:?}", lex_errs);
|
||||
|
|
Loading…
Reference in New Issue
Block a user