This commit is contained in:
Erin 2023-09-13 22:44:03 +02:00 committed by ondra05
parent 1846fe41ae
commit de94dfdfba
3 changed files with 194 additions and 34 deletions

View file

@ -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,
} }

View file

@ -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

View file

@ -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
}