diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index 75ea3398..4264994c 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -187,10 +187,12 @@ pub enum ArgName { }, Named { name: String, + location: Span, }, NamedLabeled { name: String, label: String, + location: Span, }, } @@ -270,6 +272,9 @@ pub enum BinOp { ModInt, } +pub type UntypedPattern = Pattern<(), ()>; +pub type TypedPattern = Pattern>; + #[derive(Debug, Clone, PartialEq)] pub enum Pattern { Int { diff --git a/crates/lang/src/lexer.rs b/crates/lang/src/lexer.rs index a9f329f3..504d66af 100644 --- a/crates/lang/src/lexer.rs +++ b/crates/lang/src/lexer.rs @@ -1,12 +1,9 @@ use chumsky::prelude::*; -use internment::Intern; use crate::{ast::Span, error::ParseError, token::Token}; pub fn lexer() -> impl Parser, Error = ParseError> { - let int = text::int(10) - .map(Intern::new) - .map(|value| Token::Int { value }); + let int = text::int(10).map(|value| Token::Int { value }); let op = choice(( just("==").to(Token::EqualEqual), @@ -54,7 +51,6 @@ pub fn lexer() -> impl Parser, Error = ParseError> { .ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated()) .then_ignore(just('"')) .collect::() - .map(Intern::new) .map(|value| Token::String { value }) .labelled("string"); diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index a994c8fe..0c976740 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -204,6 +204,17 @@ pub fn fn_param_parser() -> impl Parser 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()) .map_with_span(|(arg_name, annotation), span| ast::Arg { @@ -214,7 +225,27 @@ pub fn fn_param_parser() -> impl Parser impl Parser {} +pub fn expr_seq_parser() -> impl Parser { + 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 {} pub fn type_parser() -> impl Parser { recursive(|r| { @@ -313,6 +344,118 @@ pub fn pub_parser() -> impl Parser { just(Token::Pub).ignored() } +pub fn pattern_parser() -> impl Parser { + 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)] mod tests { use chumsky::prelude::*; diff --git a/crates/lang/src/token.rs b/crates/lang/src/token.rs index 864f77a1..cf6856e0 100644 --- a/crates/lang/src/token.rs +++ b/crates/lang/src/token.rs @@ -1,15 +1,13 @@ use std::fmt; -use internment::Intern; - #[derive(Clone, Debug, PartialEq, Hash, Eq)] pub enum Token { Error(char), Name { name: String }, UpName { name: String }, DiscardName { name: String }, - Int { value: Intern }, - String { value: Intern }, + Int { value: String }, + String { value: String }, // Groupings LeftParen, // ( RightParen, // ) @@ -85,8 +83,8 @@ impl fmt::Display for Token { Token::Name { name } => name, Token::UpName { name } => name, Token::DiscardName { name } => name, - Token::Int { value } => &**value, - Token::String { value } => &**value, + Token::Int { value } => value, + Token::String { value } => value, Token::LeftParen => "(", Token::RightParen => ")", Token::LeftSquare => "[",