Paths
This commit is contained in:
parent
1846fe41ae
commit
de94dfdfba
|
@ -26,22 +26,30 @@ pub enum Expr<'a> {
|
||||||
Call(ExprRef<'a>, ExprList<'a>),
|
Call(ExprRef<'a>, ExprList<'a>),
|
||||||
Binary(Spanned<BinaryOperator>, ExprRef<'a>, ExprRef<'a>),
|
Binary(Spanned<BinaryOperator>, ExprRef<'a>, ExprRef<'a>),
|
||||||
Unary(Spanned<UnaryOperator>, ExprRef<'a>),
|
Unary(Spanned<UnaryOperator>, ExprRef<'a>),
|
||||||
BindLocal(ExprRef<'a>, Spanned<Pattern>, Option<ExprList<'a>>),
|
BindLocal(Spanned<Pattern>, ExprRef<'a>, Option<ExprList<'a>>),
|
||||||
BindIn(
|
BindIn(
|
||||||
ExprRef<'a>,
|
|
||||||
Spanned<Pattern>,
|
Spanned<Pattern>,
|
||||||
|
ExprRef<'a>,
|
||||||
ExprList<'a>,
|
ExprList<'a>,
|
||||||
Option<ExprList<'a>>,
|
Option<ExprList<'a>>,
|
||||||
),
|
),
|
||||||
Match(ExprRef<'a>, &'a [(Spanned<Pattern>, SpanExpr<'a>)]),
|
|
||||||
Set(ExprRef<'a>, ExprRef<'a>),
|
Set(ExprRef<'a>, ExprRef<'a>),
|
||||||
Func(Ident, &'a [Spanned<Pattern>], ExprRef<'a>),
|
Match(ExprRef<'a>, &'a [(Spanned<Pattern>, SpanExpr<'a>)]),
|
||||||
|
Func(&'a [(Spanned<Pattern>, Spanned<Type>)], Spanned<Type>, ExprRef<'a>),
|
||||||
Block(ExprList<'a>),
|
Block(ExprList<'a>),
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Type {
|
||||||
|
Ident(Ident),
|
||||||
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
|
Literal(Literal),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::ast::{BinaryOperator, Literal, SpanExpr, UnaryOperator};
|
use super::ast::Type;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
super::{
|
super::{
|
||||||
ast::{Expr, Spanned},
|
ast::{BinaryOperator, Expr, Literal, Pattern, SpanExpr, Spanned, UnaryOperator},
|
||||||
token::Token,
|
token::Token,
|
||||||
},
|
},
|
||||||
crate::utils::Pipe,
|
crate::utils::Pipe,
|
||||||
|
@ -28,21 +28,65 @@ where
|
||||||
I: Input<'a, Token = Token, Span = SimpleSpan> + ValueInput<'a>,
|
I: Input<'a, Token = Token, Span = SimpleSpan> + ValueInput<'a>,
|
||||||
{
|
{
|
||||||
recursive(|expr| {
|
recursive(|expr| {
|
||||||
let ident = select!(Token::Ident(id) => Expr::Ident(id));
|
let ident = select!(Token::Ident(id) => id);
|
||||||
|
|
||||||
let literal = select! {
|
let literal = select! {
|
||||||
Token::Int(a) => Literal::Integer(a),
|
Token::Int(a) => Literal::Integer(a),
|
||||||
Token::String(a) => Literal::String(a)
|
Token::String(a) => Literal::String(a)
|
||||||
}
|
};
|
||||||
.map(Expr::Literal);
|
|
||||||
|
|
||||||
let atom = literal.or(ident).map_with_span(Spanned::new).or(expr
|
let pattern = select! {
|
||||||
|
Token::Ident(id) => Pattern::Ident(id),
|
||||||
|
Token::Underscore => Pattern::None,
|
||||||
|
}
|
||||||
|
.or(literal.map(Pattern::Literal))
|
||||||
|
.map_with_span(Spanned::new);
|
||||||
|
|
||||||
|
let type_ = just([Token::LeftParen, Token::RightParen])
|
||||||
|
.to(Type::Unit)
|
||||||
|
.or(ident.map(Type::Ident))
|
||||||
|
.map_with_span(Spanned::new);
|
||||||
|
|
||||||
|
let block = expr
|
||||||
|
.clone()
|
||||||
|
.separated_by(just(Token::Semicolon))
|
||||||
|
.allow_trailing()
|
||||||
|
.pipe(arena_collect)
|
||||||
|
.delimited_by(just(Token::LeftCurly), just(Token::RightCurly));
|
||||||
|
|
||||||
|
let func = just(Token::Func)
|
||||||
|
.ignore_then(
|
||||||
|
pattern
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(type_)
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.pipe(arena_collect)
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||||
|
)
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(type_)
|
||||||
|
.then(
|
||||||
|
just(Token::Equ)
|
||||||
|
.ignore_then(expr.clone())
|
||||||
|
.or(block.clone().map(Expr::Block).map_with_span(Spanned::new)),
|
||||||
|
)
|
||||||
|
.map_with_state(|((params, ret), expr), _, state| {
|
||||||
|
Expr::Func(params, ret, state.arena.alloc(expr))
|
||||||
|
});
|
||||||
|
|
||||||
|
let atom = literal
|
||||||
|
.map(Expr::Literal)
|
||||||
|
.or(just([Token::LeftParen, Token::RightParen]).to(Expr::Unit))
|
||||||
|
.or(ident.map(Expr::Ident))
|
||||||
|
.or(func)
|
||||||
|
.map_with_span(Spanned::new)
|
||||||
|
.or(expr
|
||||||
.clone()
|
.clone()
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)));
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)));
|
||||||
|
|
||||||
let call = atom
|
// <expr>(expr1, expr2, …)
|
||||||
.clone()
|
let call = atom.clone().foldl_with_state(
|
||||||
.foldl_with_state(
|
|
||||||
expr.clone()
|
expr.clone()
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
|
@ -56,11 +100,35 @@ where
|
||||||
merge_spans(expr.span, paramlist.span),
|
merge_spans(expr.span, paramlist.span),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let path = call
|
||||||
|
.clone()
|
||||||
|
.map_with_state(|item, _, state| bumpalo::vec![in state.arena; item])
|
||||||
|
.foldl(
|
||||||
|
just(Token::Dot).ignore_then(call).repeated(),
|
||||||
|
|mut v, expr| {
|
||||||
|
v.push(expr);
|
||||||
|
v
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.boxed();
|
.map(|v| Expr::Path(v.into_bump_slice()))
|
||||||
|
.map_with_span(Spanned::new);
|
||||||
|
|
||||||
let unary = call;
|
/* let unary = equivmap!(Token, UnaryOperator, [Minus, Tilde])
|
||||||
|
.map_with_span(Spanned::new)
|
||||||
|
.repeated()
|
||||||
|
.foldr_with_state(call, |op, expr, state| {
|
||||||
|
Spanned::new(
|
||||||
|
Expr::Unary(op, state.arena.alloc(expr)),
|
||||||
|
merge_spans(op.span, expr.span),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
let unary = path;
|
||||||
|
|
||||||
|
// <exprL> OP <exprR>
|
||||||
let binary = unary.clone().foldl_with_state(
|
let binary = unary.clone().foldl_with_state(
|
||||||
equivmap!(
|
equivmap!(
|
||||||
Token,
|
Token,
|
||||||
|
@ -78,31 +146,92 @@ where
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
binary.or(atom)
|
let bind = {
|
||||||
|
let start = pattern.then_ignore(just(Token::Colon)).then(expr.clone()); // <pat> := <expr>
|
||||||
|
let else_ = just(Token::Else).ignore_then(block.clone()).or_not(); // else {…}
|
||||||
|
|
||||||
|
// <pat> := <expr> [else {…}]
|
||||||
|
let local = start.clone().then(else_.clone()).map_with_state(
|
||||||
|
|((pat, expr), else_), _, state| {
|
||||||
|
Expr::BindLocal(pat, &*state.arena.alloc(expr), else_)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// <pat> := <expr> {…} else {…}
|
||||||
|
let in_ = start.then(block.clone()).then(else_).map_with_state(
|
||||||
|
|(((pat, expr), block), else_), _, state| {
|
||||||
|
Expr::BindIn(pat, &*state.arena.alloc(expr), block, else_)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
in_.or(local)
|
||||||
|
};
|
||||||
|
|
||||||
|
// <atom> ← <expr>
|
||||||
|
let set = atom
|
||||||
|
.clone()
|
||||||
|
.then_ignore(just(Token::LArrow))
|
||||||
|
.then(expr.clone())
|
||||||
|
.map_with_state(|(place, expr), _, state| {
|
||||||
|
Expr::Set(state.arena.alloc(place), state.arena.alloc(expr))
|
||||||
|
});
|
||||||
|
|
||||||
|
// <expr>.match { <pat> → <expr>, … }
|
||||||
|
let match_ = atom
|
||||||
|
.clone()
|
||||||
|
.then_ignore(just([Token::Dot, Token::Match]))
|
||||||
|
.then(
|
||||||
|
pattern
|
||||||
|
.then_ignore(just(Token::RArrow))
|
||||||
|
.then(expr)
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.pipe(arena_collect)
|
||||||
|
.delimited_by(just(Token::LeftCurly), just(Token::RightCurly)),
|
||||||
|
)
|
||||||
|
.map_with_state(|(expr, branches), _, state| {
|
||||||
|
Expr::Match(state.arena.alloc(expr), branches)
|
||||||
|
});
|
||||||
|
|
||||||
|
bind.or(set)
|
||||||
|
.or(match_)
|
||||||
|
.or(block.map(Expr::Block))
|
||||||
|
.map_with_span(Spanned::new)
|
||||||
|
.or(binary)
|
||||||
|
.or(atom)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
}
|
}
|
||||||
pub type Extra<'a> = Full<Rich<'a, Token>, State<'a>, ()>;
|
|
||||||
|
type Extra<'a> = Full<Rich<'a, Token>, State<'a>, ()>;
|
||||||
|
type ParseResult = ();
|
||||||
|
|
||||||
pub fn parse_input<'a>(
|
pub fn parse_input<'a>(
|
||||||
input: impl ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
input: impl ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
) {
|
) -> ParseResult {
|
||||||
println!("{:?}", expr().parse_with_state(input, &mut State { arena }));
|
println!(
|
||||||
|
"{:?}",
|
||||||
|
expr()
|
||||||
|
.separated_by(just(Token::Semicolon))
|
||||||
|
.allow_trailing()
|
||||||
|
.pipe(arena_collect)
|
||||||
|
.parse_with_state(input, &mut State { arena })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_iter(
|
pub fn parse_iter(
|
||||||
input: impl Iterator<Item = (Token, SimpleSpan)>,
|
input: impl Iterator<Item = (Token, SimpleSpan)>,
|
||||||
eoi: impl Into<SimpleSpan>,
|
eoi: impl Into<SimpleSpan>,
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
) {
|
) -> ParseResult {
|
||||||
parse_input(Stream::from_iter(input).spanned(eoi.into()), arena)
|
parse_input(Stream::from_iter(input).spanned(eoi.into()), arena)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_lexer(input: Lexer<Token>, arena: &Bump) {
|
pub fn parse_lexer(input: Lexer<Token>, arena: &Bump) -> ParseResult {
|
||||||
let end = input.span().end;
|
let end = input.span().end;
|
||||||
parse_iter(
|
parse_iter(
|
||||||
input
|
input
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use lasso::Spur;
|
use lasso::Spur;
|
||||||
|
use logos::Lexer;
|
||||||
|
|
||||||
use {lasso::Rodeo, logos::Logos};
|
use {lasso::Rodeo, logos::Logos};
|
||||||
|
|
||||||
|
@ -25,12 +26,14 @@ pub enum Token {
|
||||||
#[token("}")] RightCurly,
|
#[token("}")] RightCurly,
|
||||||
#[token(".")] Dot,
|
#[token(".")] Dot,
|
||||||
#[token(",")] Comma,
|
#[token(",")] Comma,
|
||||||
|
#[token(":")] Colon,
|
||||||
#[token(";")] Semicolon,
|
#[token(";")] Semicolon,
|
||||||
#[token(":=")] //__
|
#[token("_")] Underscore,
|
||||||
#[token("≔") ] Bind,
|
|
||||||
|
|
||||||
#[token("←")] //_
|
#[token("←")] //____
|
||||||
#[token("<-")] Set,
|
#[token("<-")] LArrow,
|
||||||
|
#[token("→")] //____
|
||||||
|
#[token("->")] RArrow,
|
||||||
|
|
||||||
#[token(":>")] Pipe,
|
#[token(":>")] Pipe,
|
||||||
|
|
||||||
|
@ -66,6 +69,7 @@ pub enum Token {
|
||||||
|l| l.extras.interner.get_or_intern(l.slice())
|
|l| l.extras.interner.get_or_intern(l.slice())
|
||||||
)] Ident(Spur),
|
)] Ident(Spur),
|
||||||
|
|
||||||
|
#[token("»", better_string)]
|
||||||
#[regex(
|
#[regex(
|
||||||
"\"[^\"]*\"",
|
"\"[^\"]*\"",
|
||||||
|l| {
|
|l| {
|
||||||
|
@ -87,3 +91,22 @@ pub enum Token {
|
||||||
|
|
||||||
Invalid,
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For Evy, with love.
|
||||||
|
fn better_string(lexer: &mut Lexer<Token>) -> Option<Spur> {
|
||||||
|
let mut count = 1;
|
||||||
|
for (ix, chr) in lexer.remainder().char_indices() {
|
||||||
|
match chr {
|
||||||
|
'«' => count -= 1,
|
||||||
|
'»' => count += 1,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
let slice = &lexer.remainder()[..ix];
|
||||||
|
lexer.bump(ix + '«'.len_utf8());
|
||||||
|
return Some(lexer.extras.interner.get_or_intern(slice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue