feat: beginnings of expr parsing

This commit is contained in:
rvcas 2022-08-17 21:54:24 -04:00
parent d87bb17a27
commit 3bc507c9e8
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
4 changed files with 154 additions and 12 deletions

View File

@ -187,10 +187,12 @@ pub enum ArgName {
}, },
Named { Named {
name: String, name: String,
location: Span,
}, },
NamedLabeled { NamedLabeled {
name: String, name: String,
label: String, label: String,
location: Span,
}, },
} }
@ -270,6 +272,9 @@ pub enum BinOp {
ModInt, ModInt,
} }
pub type UntypedPattern = Pattern<(), ()>;
pub type TypedPattern = Pattern<PatternConstructor, Arc<Type>>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Pattern<Constructor, Type> { pub enum Pattern<Constructor, Type> {
Int { Int {

View File

@ -1,12 +1,9 @@
use chumsky::prelude::*; use chumsky::prelude::*;
use internment::Intern;
use crate::{ast::Span, error::ParseError, token::Token}; use crate::{ast::Span, error::ParseError, token::Token};
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> { pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
let int = text::int(10) let int = text::int(10).map(|value| Token::Int { value });
.map(Intern::new)
.map(|value| Token::Int { value });
let op = choice(( let op = choice((
just("==").to(Token::EqualEqual), just("==").to(Token::EqualEqual),
@ -54,7 +51,6 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated()) .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
.then_ignore(just('"')) .then_ignore(just('"'))
.collect::<String>() .collect::<String>()
.map(Intern::new)
.map(|value| Token::String { value }) .map(|value| Token::String { value })
.labelled("string"); .labelled("string");

View File

@ -204,6 +204,17 @@ pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseErr
location: span, location: span,
} }
}), }),
select! {Token::Name {name} => name}
.then(select! {Token::Name {name} => name})
.map_with_span(|(label, name), span| ast::ArgName::NamedLabeled {
label,
name,
location: span,
}),
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
name,
location: span,
}),
)) ))
.then(just(Token::Colon).ignore_then(type_parser()).or_not()) .then(just(Token::Colon).ignore_then(type_parser()).or_not())
.map_with_span(|(arg_name, annotation), span| ast::Arg { .map_with_span(|(arg_name, annotation), span| ast::Arg {
@ -214,7 +225,27 @@ pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseErr
}) })
} }
pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {} pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
recursive(|r| {
choice((just(Token::Try)
.ignore_then(pattern_parser())
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
.then_ignore(just(Token::Equal))
.then(expr_parser())
.then(r)
.map_with_span(|(((pattern, annotation), value), then_), span| {
expr::UntypedExpr::Try {
location: span,
value: Box::new(value),
pattern,
then: Box::new(then_),
annotation,
}
}),))
})
}
pub fn expr_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {}
pub fn type_parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> { pub fn type_parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
recursive(|r| { recursive(|r| {
@ -313,6 +344,118 @@ pub fn pub_parser() -> impl Parser<Token, (), Error = ParseError> {
just(Token::Pub).ignored() just(Token::Pub).ignored()
} }
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
recursive(|r| {
let constructor_pattern_arg_parser = choice((
select! {Token::Name {name} => name}
.then_ignore(just(Token::Colon))
.then(r.clone())
.map_with_span(|(name, pattern), span| ast::CallArg {
location: span,
label: Some(name),
value: pattern,
}),
r.map_with_span(|pattern, span| ast::CallArg {
location: span,
value: pattern,
label: None,
}),
));
let constructor_pattern_args_parser = constructor_pattern_arg_parser
.separated_by(just(Token::Comma))
.allow_trailing()
.then(
just(Token::DotDot)
.then_ignore(just(Token::Comma).or_not())
.ignored()
.or_not(),
)
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.or_not()
.map(|opt_args| {
opt_args
.map(|(a, b)| (a, b.is_some()))
.unwrap_or_else(|| (vec![], false))
});
let constructor_pattern_parser =
select! {Token::UpName { name } => name}.then(constructor_pattern_args_parser);
choice((
select! { Token::Name {name} => name }
.then(
just(Token::Dot)
.ignore_then(constructor_pattern_parser.clone())
.or_not(),
)
.map_with_span(|(name, opt_pattern), span| {
if let Some((c_name, (arguments, with_spread))) = opt_pattern {
ast::UntypedPattern::Constructor {
location: span,
name: c_name,
arguments,
module: Some(name),
constructor: (),
with_spread,
tipo: (),
}
} else {
ast::UntypedPattern::Var {
location: span,
name,
}
}
}),
constructor_pattern_parser.map_with_span(|(name, (arguments, with_spread)), span| {
ast::UntypedPattern::Constructor {
location: span,
name,
arguments,
module: None,
constructor: (),
with_spread,
tipo: (),
}
}),
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
ast::UntypedPattern::Discard {
name,
location: span,
}
}),
select! {Token::String {value} => value}.map_with_span(|value, span| {
ast::UntypedPattern::String {
location: span,
value,
}
}),
select! {Token::Int {value} => value}.map_with_span(|value, span| {
ast::UntypedPattern::Int {
location: span,
value,
}
}),
))
.then(
just(Token::As)
.ignore_then(select! { Token::Name {name} => name})
.or_not(),
)
.map_with_span(|(pattern, opt_as), span| {
if let Some(name) = opt_as {
ast::UntypedPattern::Assign {
name,
location: span,
pattern: Box::new(pattern),
}
} else {
pattern
}
})
})
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use chumsky::prelude::*; use chumsky::prelude::*;

View File

@ -1,15 +1,13 @@
use std::fmt; use std::fmt;
use internment::Intern;
#[derive(Clone, Debug, PartialEq, Hash, Eq)] #[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub enum Token { pub enum Token {
Error(char), Error(char),
Name { name: String }, Name { name: String },
UpName { name: String }, UpName { name: String },
DiscardName { name: String }, DiscardName { name: String },
Int { value: Intern<String> }, Int { value: String },
String { value: Intern<String> }, String { value: String },
// Groupings // Groupings
LeftParen, // ( LeftParen, // (
RightParen, // ) RightParen, // )
@ -85,8 +83,8 @@ impl fmt::Display for Token {
Token::Name { name } => name, Token::Name { name } => name,
Token::UpName { name } => name, Token::UpName { name } => name,
Token::DiscardName { name } => name, Token::DiscardName { name } => name,
Token::Int { value } => &**value, Token::Int { value } => value,
Token::String { value } => &**value, Token::String { value } => value,
Token::LeftParen => "(", Token::LeftParen => "(",
Token::RightParen => ")", Token::RightParen => ")",
Token::LeftSquare => "[", Token::LeftSquare => "[",