feat: finish moving definitions and start exprs
This commit is contained in:
parent
fc580d4fa0
commit
3339d41fdd
|
@ -1,19 +1,23 @@
|
||||||
|
mod annotation;
|
||||||
pub mod definitions;
|
pub mod definitions;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
mod expr;
|
||||||
pub mod extra;
|
pub mod extra;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
mod module;
|
mod module;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub use annotation::parser as annotation;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, BinOp, ByteArrayFormatPreference, Span, TraceKind, UnOp, CAPTURE_VARIABLE},
|
ast::{self, BinOp, ByteArrayFormatPreference, Span, UnOp, CAPTURE_VARIABLE},
|
||||||
expr,
|
expr::{FnStyle, UntypedExpr},
|
||||||
};
|
};
|
||||||
use chumsky::{chain::Chain, prelude::*};
|
use chumsky::{chain::Chain, prelude::*};
|
||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
use extra::ModuleExtra;
|
use extra::ModuleExtra;
|
||||||
use token::{Base, Token};
|
use token::Token;
|
||||||
use vec1::{vec1, Vec1};
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
pub fn module(
|
pub fn module(
|
||||||
|
@ -74,7 +78,9 @@ pub fn module(
|
||||||
Token::NewLine => None,
|
Token::NewLine => None,
|
||||||
_ => Some((token, *span)),
|
_ => Some((token, *span)),
|
||||||
};
|
};
|
||||||
|
|
||||||
previous_is_newline = current_is_newline;
|
previous_is_newline = current_is_newline;
|
||||||
|
|
||||||
result
|
result
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -92,152 +98,6 @@ pub fn module(
|
||||||
Ok((module, extra))
|
Ok((module, extra))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseError> {
|
|
||||||
let constant_string_parser =
|
|
||||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
|
||||||
ast::Constant::String {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let constant_int_parser =
|
|
||||||
select! {Token::Int {value, base} => (value, base)}.map_with_span(|(value, base), span| {
|
|
||||||
ast::Constant::Int {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
base,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let constant_bytearray_parser =
|
|
||||||
bytearray_parser().map_with_span(|(preferred_format, bytes), span| {
|
|
||||||
ast::Constant::ByteArray {
|
|
||||||
location: span,
|
|
||||||
bytes,
|
|
||||||
preferred_format,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
choice((
|
|
||||||
constant_string_parser,
|
|
||||||
constant_int_parser,
|
|
||||||
constant_bytearray_parser,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bytearray_parser(
|
|
||||||
) -> impl Parser<Token, (ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
|
|
||||||
let bytearray_list_parser = just(Token::Hash)
|
|
||||||
.ignore_then(
|
|
||||||
select! {Token::Int {value, base, ..} => (value, base)}
|
|
||||||
.validate(|(value, base), span, emit| {
|
|
||||||
let byte: u8 = match value.parse() {
|
|
||||||
Ok(b) => b,
|
|
||||||
Err(_) => {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
span,
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Byte),
|
|
||||||
));
|
|
||||||
0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(byte, base)
|
|
||||||
})
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
|
|
||||||
)
|
|
||||||
.validate(|bytes, span, emit| {
|
|
||||||
let base = bytes.iter().fold(Ok(None), |acc, (_, base)| match acc {
|
|
||||||
Ok(None) => Ok(Some(base)),
|
|
||||||
Ok(Some(previous_base)) if previous_base == base => Ok(Some(base)),
|
|
||||||
_ => Err(()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let base = match base {
|
|
||||||
Err(()) => {
|
|
||||||
emit(ParseError::hybrid_notation_in_bytearray(span));
|
|
||||||
Base::Decimal {
|
|
||||||
numeric_underscore: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None) => Base::Decimal {
|
|
||||||
numeric_underscore: false,
|
|
||||||
},
|
|
||||||
Ok(Some(base)) => *base,
|
|
||||||
};
|
|
||||||
|
|
||||||
(bytes.into_iter().map(|(b, _)| b).collect::<Vec<u8>>(), base)
|
|
||||||
})
|
|
||||||
.map(|(bytes, base)| (ByteArrayFormatPreference::ArrayOfBytes(base), bytes));
|
|
||||||
|
|
||||||
let bytearray_hexstring_parser =
|
|
||||||
just(Token::Hash)
|
|
||||||
.ignore_then(select! {Token::ByteString {value} => value}.validate(
|
|
||||||
|value, span, emit| match hex::decode(value) {
|
|
||||||
Ok(bytes) => bytes,
|
|
||||||
Err(_) => {
|
|
||||||
emit(ParseError::malformed_base16_string_literal(span));
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.map(|token| (ByteArrayFormatPreference::HexadecimalString, token));
|
|
||||||
|
|
||||||
let bytearray_utf8_parser = select! {Token::ByteString {value} => value.into_bytes() }
|
|
||||||
.map(|token| (ByteArrayFormatPreference::Utf8String, token));
|
|
||||||
|
|
||||||
choice((
|
|
||||||
bytearray_list_parser,
|
|
||||||
bytearray_hexstring_parser,
|
|
||||||
bytearray_utf8_parser,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fn_param_parser(
|
|
||||||
is_validator_param: bool,
|
|
||||||
) -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
|
||||||
choice((
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.then(select! {Token::DiscardName {name} => name})
|
|
||||||
.map_with_span(|(label, name), span| ast::ArgName::Discarded {
|
|
||||||
label,
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
}),
|
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
|
||||||
ast::ArgName::Discarded {
|
|
||||||
label: name.clone(),
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.then(select! {Token::Name {name} => name})
|
|
||||||
.map_with_span(move |(label, name), span| ast::ArgName::Named {
|
|
||||||
label,
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
is_validator_param,
|
|
||||||
}),
|
|
||||||
select! {Token::Name {name} => name}.map_with_span(move |name, span| ast::ArgName::Named {
|
|
||||||
label: name.clone(),
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
is_validator_param,
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
|
||||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
|
||||||
location: span,
|
|
||||||
annotation,
|
|
||||||
tipo: (),
|
|
||||||
arg_name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||||
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
||||||
choice((
|
choice((
|
||||||
|
@ -255,7 +115,7 @@ pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = Par
|
||||||
is_validator_param: false,
|
is_validator_param: false,
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||||
location: span,
|
location: span,
|
||||||
annotation,
|
annotation,
|
||||||
|
@ -269,13 +129,13 @@ pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = Par
|
||||||
// This is mostly convenient so that todo & error works with either @"..." or plain "...".
|
// This is mostly convenient so that todo & error works with either @"..." or plain "...".
|
||||||
// In this particular context, there's actually no ambiguity about the right-hand-side, so
|
// In this particular context, there's actually no ambiguity about the right-hand-side, so
|
||||||
// we can provide this syntactic sugar.
|
// we can provide this syntactic sugar.
|
||||||
fn flexible_string_literal(expr: expr::UntypedExpr) -> expr::UntypedExpr {
|
fn flexible_string_literal(expr: UntypedExpr) -> UntypedExpr {
|
||||||
match expr {
|
match expr {
|
||||||
expr::UntypedExpr::ByteArray {
|
UntypedExpr::ByteArray {
|
||||||
preferred_format: ByteArrayFormatPreference::Utf8String,
|
preferred_format: ByteArrayFormatPreference::Utf8String,
|
||||||
bytes,
|
bytes,
|
||||||
location,
|
location,
|
||||||
} => expr::UntypedExpr::String {
|
} => UntypedExpr::String {
|
||||||
location,
|
location,
|
||||||
value: String::from_utf8(bytes).unwrap(),
|
value: String::from_utf8(bytes).unwrap(),
|
||||||
},
|
},
|
||||||
|
@ -283,49 +143,20 @@ fn flexible_string_literal(expr: expr::UntypedExpr) -> expr::UntypedExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
|
|
||||||
recursive(|r| {
|
|
||||||
choice((
|
|
||||||
just(Token::Trace)
|
|
||||||
.ignore_then(expr_parser(r.clone()))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
|
|
||||||
kind: TraceKind::Trace,
|
|
||||||
location: span,
|
|
||||||
then: Box::new(then_),
|
|
||||||
text: Box::new(flexible_string_literal(text)),
|
|
||||||
}),
|
|
||||||
just(Token::ErrorTerm)
|
|
||||||
.ignore_then(expr_parser(r.clone()).or_not())
|
|
||||||
.map_with_span(|reason, span| {
|
|
||||||
expr::UntypedExpr::error(span, reason.map(flexible_string_literal))
|
|
||||||
}),
|
|
||||||
just(Token::Todo)
|
|
||||||
.ignore_then(expr_parser(r.clone()).or_not())
|
|
||||||
.map_with_span(|reason, span| {
|
|
||||||
expr::UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
|
||||||
}),
|
|
||||||
expr_parser(r.clone())
|
|
||||||
.then(r.repeated())
|
|
||||||
.foldl(|current, next| current.append_in_sequence(next)),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expr_parser(
|
pub fn expr_parser(
|
||||||
seq_r: Recursive<'_, Token, expr::UntypedExpr, ParseError>,
|
seq_r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
) -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> + '_ {
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
recursive(|r| {
|
recursive(|r| {
|
||||||
let string_parser =
|
let string_parser =
|
||||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||||
expr::UntypedExpr::String {
|
UntypedExpr::String {
|
||||||
location: span,
|
location: span,
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let int_parser = select! { Token::Int {value, base} => (value, base)}.map_with_span(
|
let int_parser = select! { Token::Int {value, base} => (value, base)}.map_with_span(
|
||||||
|(value, base), span| expr::UntypedExpr::Int {
|
|(value, base), span| UntypedExpr::Int {
|
||||||
location: span,
|
location: span,
|
||||||
value,
|
value,
|
||||||
base,
|
base,
|
||||||
|
@ -357,7 +188,7 @@ pub fn expr_parser(
|
||||||
select! {Token::Name {name} => name}.map_with_span(
|
select! {Token::Name {name} => name}.map_with_span(
|
||||||
|name, span| ast::UntypedRecordUpdateArg {
|
|name, span| ast::UntypedRecordUpdateArg {
|
||||||
location: span,
|
location: span,
|
||||||
value: expr::UntypedExpr::Var {
|
value: UntypedExpr::Var {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
location: span,
|
location: span,
|
||||||
},
|
},
|
||||||
|
@ -375,16 +206,16 @@ pub fn expr_parser(
|
||||||
)
|
)
|
||||||
.map(|((module, (name, n_span)), ((spread, opt_args), span))| {
|
.map(|((module, (name, n_span)), ((spread, opt_args), span))| {
|
||||||
let constructor = if let Some((module, m_span)) = module {
|
let constructor = if let Some((module, m_span)) = module {
|
||||||
expr::UntypedExpr::FieldAccess {
|
UntypedExpr::FieldAccess {
|
||||||
location: m_span.union(n_span),
|
location: m_span.union(n_span),
|
||||||
label: name,
|
label: name,
|
||||||
container: Box::new(expr::UntypedExpr::Var {
|
container: Box::new(UntypedExpr::Var {
|
||||||
location: m_span,
|
location: m_span,
|
||||||
name: module,
|
name: module,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
location: n_span,
|
location: n_span,
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
|
@ -399,7 +230,7 @@ pub fn expr_parser(
|
||||||
location,
|
location,
|
||||||
};
|
};
|
||||||
|
|
||||||
expr::UntypedExpr::RecordUpdate {
|
UntypedExpr::RecordUpdate {
|
||||||
location: constructor.location().union(span),
|
location: constructor.location().union(span),
|
||||||
constructor: Box::new(constructor),
|
constructor: Box::new(constructor),
|
||||||
spread,
|
spread,
|
||||||
|
@ -430,7 +261,7 @@ pub fn expr_parser(
|
||||||
Some(error::Pattern::Discard),
|
Some(error::Pattern::Discard),
|
||||||
));
|
));
|
||||||
|
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
location: span,
|
location: span,
|
||||||
name: CAPTURE_VARIABLE.to_string(),
|
name: CAPTURE_VARIABLE.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -445,7 +276,7 @@ pub fn expr_parser(
|
||||||
choice((
|
choice((
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
(
|
(
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
location: span,
|
location: span,
|
||||||
},
|
},
|
||||||
|
@ -461,7 +292,7 @@ pub fn expr_parser(
|
||||||
));
|
));
|
||||||
|
|
||||||
(
|
(
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
location: span,
|
location: span,
|
||||||
name: CAPTURE_VARIABLE.to_string(),
|
name: CAPTURE_VARIABLE.to_string(),
|
||||||
},
|
},
|
||||||
|
@ -510,7 +341,7 @@ pub fn expr_parser(
|
||||||
Some(error::Pattern::Discard),
|
Some(error::Pattern::Discard),
|
||||||
));
|
));
|
||||||
|
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
location: span,
|
location: span,
|
||||||
name: CAPTURE_VARIABLE.to_string(),
|
name: CAPTURE_VARIABLE.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -529,22 +360,22 @@ pub fn expr_parser(
|
||||||
))
|
))
|
||||||
.map_with_span(|((module, (name, n_span)), arguments), span| {
|
.map_with_span(|((module, (name, n_span)), arguments), span| {
|
||||||
let fun = if let Some((module, m_span)) = module {
|
let fun = if let Some((module, m_span)) = module {
|
||||||
expr::UntypedExpr::FieldAccess {
|
UntypedExpr::FieldAccess {
|
||||||
location: m_span.union(n_span),
|
location: m_span.union(n_span),
|
||||||
label: name,
|
label: name,
|
||||||
container: Box::new(expr::UntypedExpr::Var {
|
container: Box::new(UntypedExpr::Var {
|
||||||
location: m_span,
|
location: m_span,
|
||||||
name: module,
|
name: module,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
expr::UntypedExpr::Var {
|
UntypedExpr::Var {
|
||||||
location: n_span,
|
location: n_span,
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
expr::UntypedExpr::Call {
|
UntypedExpr::Call {
|
||||||
arguments,
|
arguments,
|
||||||
fun: Box::new(fun),
|
fun: Box::new(fun),
|
||||||
location: span,
|
location: span,
|
||||||
|
@ -555,22 +386,20 @@ pub fn expr_parser(
|
||||||
.map_with_span(|module, span| (module, span))
|
.map_with_span(|module, span| (module, span))
|
||||||
.then_ignore(just(Token::Dot))
|
.then_ignore(just(Token::Dot))
|
||||||
.then(select! {Token::UpName { name } => name})
|
.then(select! {Token::UpName { name } => name})
|
||||||
.map_with_span(
|
.map_with_span(|((module, m_span), name), span| UntypedExpr::FieldAccess {
|
||||||
|((module, m_span), name), span| expr::UntypedExpr::FieldAccess {
|
location: span,
|
||||||
location: span,
|
label: name,
|
||||||
label: name,
|
container: Box::new(UntypedExpr::Var {
|
||||||
container: Box::new(expr::UntypedExpr::Var {
|
location: m_span,
|
||||||
location: m_span,
|
name: module,
|
||||||
name: module,
|
}),
|
||||||
}),
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let var_parser = select! {
|
let var_parser = select! {
|
||||||
Token::Name { name } => name,
|
Token::Name { name } => name,
|
||||||
Token::UpName { name } => name,
|
Token::UpName { name } => name,
|
||||||
}
|
}
|
||||||
.map_with_span(|name, span| expr::UntypedExpr::Var {
|
.map_with_span(|name, span| UntypedExpr::Var {
|
||||||
location: span,
|
location: span,
|
||||||
name,
|
name,
|
||||||
});
|
});
|
||||||
|
@ -584,13 +413,13 @@ pub fn expr_parser(
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
just(Token::RightParen),
|
just(Token::RightParen),
|
||||||
)
|
)
|
||||||
.map_with_span(|elems, span| expr::UntypedExpr::Tuple {
|
.map_with_span(|elems, span| UntypedExpr::Tuple {
|
||||||
location: span,
|
location: span,
|
||||||
elems,
|
elems,
|
||||||
});
|
});
|
||||||
|
|
||||||
let bytearray = bytearray_parser().map_with_span(|(preferred_format, bytes), span| {
|
let bytearray = utils::bytearray().map_with_span(|(preferred_format, bytes), span| {
|
||||||
expr::UntypedExpr::ByteArray {
|
UntypedExpr::ByteArray {
|
||||||
location: span,
|
location: span,
|
||||||
bytes,
|
bytes,
|
||||||
preferred_format,
|
preferred_format,
|
||||||
|
@ -610,7 +439,7 @@ pub fn expr_parser(
|
||||||
)))
|
)))
|
||||||
.then_ignore(just(Token::RightSquare))
|
.then_ignore(just(Token::RightSquare))
|
||||||
// TODO: check if tail.is_some and elements.is_empty then return ListSpreadWithoutElements error
|
// TODO: check if tail.is_some and elements.is_empty then return ListSpreadWithoutElements error
|
||||||
.map_with_span(|(elements, tail), span| expr::UntypedExpr::List {
|
.map_with_span(|(elements, tail), span| UntypedExpr::List {
|
||||||
location: span,
|
location: span,
|
||||||
elements,
|
elements,
|
||||||
tail,
|
tail,
|
||||||
|
@ -633,14 +462,14 @@ pub fn expr_parser(
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||||
)
|
)
|
||||||
.then(just(Token::RArrow).ignore_then(type_parser()).or_not())
|
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
||||||
.then(seq_r.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)))
|
.then(seq_r.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)))
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((arguments, return_annotation), body), span| expr::UntypedExpr::Fn {
|
|((arguments, return_annotation), body), span| UntypedExpr::Fn {
|
||||||
arguments,
|
arguments,
|
||||||
body: Box::new(body),
|
body: Box::new(body),
|
||||||
location: span,
|
location: span,
|
||||||
fn_style: expr::FnStyle::Plain,
|
fn_style: FnStyle::Plain,
|
||||||
return_annotation,
|
return_annotation,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -703,24 +532,24 @@ pub fn expr_parser(
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let body = expr::UntypedExpr::BinOp {
|
let body = UntypedExpr::BinOp {
|
||||||
location,
|
location,
|
||||||
name,
|
name,
|
||||||
left: Box::new(expr::UntypedExpr::Var {
|
left: Box::new(UntypedExpr::Var {
|
||||||
location,
|
location,
|
||||||
name: "left".to_string(),
|
name: "left".to_string(),
|
||||||
}),
|
}),
|
||||||
right: Box::new(expr::UntypedExpr::Var {
|
right: Box::new(UntypedExpr::Var {
|
||||||
location,
|
location,
|
||||||
name: "right".to_string(),
|
name: "right".to_string(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
expr::UntypedExpr::Fn {
|
UntypedExpr::Fn {
|
||||||
arguments,
|
arguments,
|
||||||
body: Box::new(body),
|
body: Box::new(body),
|
||||||
return_annotation,
|
return_annotation,
|
||||||
fn_style: expr::FnStyle::BinOp(name),
|
fn_style: FnStyle::BinOp(name),
|
||||||
location,
|
location,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -754,7 +583,7 @@ pub fn expr_parser(
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.map_with_span(|reason, span| {
|
.map_with_span(|reason, span| {
|
||||||
expr::UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
||||||
}),
|
}),
|
||||||
just(Token::ErrorTerm)
|
just(Token::ErrorTerm)
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
|
@ -763,7 +592,7 @@ pub fn expr_parser(
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.map_with_span(|reason, span| {
|
.map_with_span(|reason, span| {
|
||||||
expr::UntypedExpr::error(span, reason.map(flexible_string_literal))
|
UntypedExpr::error(span, reason.map(flexible_string_literal))
|
||||||
}),
|
}),
|
||||||
)))
|
)))
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|
@ -787,7 +616,7 @@ pub fn expr_parser(
|
||||||
// TODO: If clauses are empty we should return ParseErrorType::NoCaseClause
|
// TODO: If clauses are empty we should return ParseErrorType::NoCaseClause
|
||||||
.then(when_clause_parser.repeated())
|
.then(when_clause_parser.repeated())
|
||||||
.then_ignore(just(Token::RightBrace))
|
.then_ignore(just(Token::RightBrace))
|
||||||
.map_with_span(|(subject, clauses), span| expr::UntypedExpr::When {
|
.map_with_span(|(subject, clauses), span| UntypedExpr::When {
|
||||||
location: span,
|
location: span,
|
||||||
subject,
|
subject,
|
||||||
clauses,
|
clauses,
|
||||||
|
@ -795,11 +624,11 @@ pub fn expr_parser(
|
||||||
|
|
||||||
let let_parser = just(Token::Let)
|
let let_parser = just(Token::Let)
|
||||||
.ignore_then(pattern_parser())
|
.ignore_then(pattern_parser())
|
||||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.then_ignore(just(Token::Equal))
|
.then_ignore(just(Token::Equal))
|
||||||
.then(r.clone())
|
.then(r.clone())
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((pattern, annotation), value), span| expr::UntypedExpr::Assignment {
|
|((pattern, annotation), value), span| UntypedExpr::Assignment {
|
||||||
location: span,
|
location: span,
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
pattern,
|
pattern,
|
||||||
|
@ -810,11 +639,11 @@ pub fn expr_parser(
|
||||||
|
|
||||||
let expect_parser = just(Token::Expect)
|
let expect_parser = just(Token::Expect)
|
||||||
.ignore_then(pattern_parser())
|
.ignore_then(pattern_parser())
|
||||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
.then_ignore(just(Token::Equal))
|
.then_ignore(just(Token::Equal))
|
||||||
.then(r.clone())
|
.then(r.clone())
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|((pattern, annotation), value), span| expr::UntypedExpr::Assignment {
|
|((pattern, annotation), value), span| UntypedExpr::Assignment {
|
||||||
location: span,
|
location: span,
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
pattern,
|
pattern,
|
||||||
|
@ -850,7 +679,7 @@ pub fn expr_parser(
|
||||||
|
|
||||||
branches.extend(alternative_branches);
|
branches.extend(alternative_branches);
|
||||||
|
|
||||||
expr::UntypedExpr::If {
|
UntypedExpr::If {
|
||||||
location: span,
|
location: span,
|
||||||
branches,
|
branches,
|
||||||
final_else: Box::new(final_else),
|
final_else: Box::new(final_else),
|
||||||
|
@ -879,7 +708,7 @@ pub fn expr_parser(
|
||||||
// Parsing a function call into the appropriate structure
|
// Parsing a function call into the appropriate structure
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ParserArg {
|
enum ParserArg {
|
||||||
Arg(Box<ast::CallArg<expr::UntypedExpr>>),
|
Arg(Box<ast::CallArg<UntypedExpr>>),
|
||||||
Hole {
|
Hole {
|
||||||
location: Span,
|
location: Span,
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
|
@ -971,7 +800,7 @@ pub fn expr_parser(
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
label,
|
label,
|
||||||
location,
|
location,
|
||||||
value: expr::UntypedExpr::Var {
|
value: UntypedExpr::Var {
|
||||||
location,
|
location,
|
||||||
name: format!("{CAPTURE_VARIABLE}__{index}"),
|
name: format!("{CAPTURE_VARIABLE}__{index}"),
|
||||||
},
|
},
|
||||||
|
@ -980,7 +809,7 @@ pub fn expr_parser(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let call = expr::UntypedExpr::Call {
|
let call = UntypedExpr::Call {
|
||||||
location: expr.location().union(span),
|
location: expr.location().union(span),
|
||||||
fun: Box::new(expr),
|
fun: Box::new(expr),
|
||||||
arguments: args,
|
arguments: args,
|
||||||
|
@ -989,9 +818,9 @@ pub fn expr_parser(
|
||||||
if holes.is_empty() {
|
if holes.is_empty() {
|
||||||
call
|
call
|
||||||
} else {
|
} else {
|
||||||
expr::UntypedExpr::Fn {
|
UntypedExpr::Fn {
|
||||||
location: call.location(),
|
location: call.location(),
|
||||||
fn_style: expr::FnStyle::Capture,
|
fn_style: FnStyle::Capture,
|
||||||
arguments: holes,
|
arguments: holes,
|
||||||
body: Box::new(call),
|
body: Box::new(call),
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
|
@ -999,13 +828,13 @@ pub fn expr_parser(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Chain::FieldAccess(label, span) => expr::UntypedExpr::FieldAccess {
|
Chain::FieldAccess(label, span) => UntypedExpr::FieldAccess {
|
||||||
location: expr.location().union(span),
|
location: expr.location().union(span),
|
||||||
label,
|
label,
|
||||||
container: Box::new(expr),
|
container: Box::new(expr),
|
||||||
},
|
},
|
||||||
|
|
||||||
Chain::TupleIndex(index, span) => expr::UntypedExpr::TupleIndex {
|
Chain::TupleIndex(index, span) => UntypedExpr::TupleIndex {
|
||||||
location: expr.location().union(span),
|
location: expr.location().union(span),
|
||||||
index,
|
index,
|
||||||
tuple: Box::new(expr),
|
tuple: Box::new(expr),
|
||||||
|
@ -1014,7 +843,7 @@ pub fn expr_parser(
|
||||||
|
|
||||||
let debug = chained.then(just(Token::Question).or_not()).map_with_span(
|
let debug = chained.then(just(Token::Question).or_not()).map_with_span(
|
||||||
|(value, token), location| match token {
|
|(value, token), location| match token {
|
||||||
Some(_) => expr::UntypedExpr::TraceIfFalse {
|
Some(_) => UntypedExpr::TraceIfFalse {
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
location,
|
location,
|
||||||
},
|
},
|
||||||
|
@ -1045,7 +874,7 @@ pub fn expr_parser(
|
||||||
.map_with_span(|op, span| (op, span))
|
.map_with_span(|op, span| (op, span))
|
||||||
.repeated()
|
.repeated()
|
||||||
.then(debug)
|
.then(debug)
|
||||||
.foldr(|(un_op, span), value| expr::UntypedExpr::UnOp {
|
.foldr(|(un_op, span), value| UntypedExpr::UnOp {
|
||||||
op: un_op,
|
op: un_op,
|
||||||
location: span.union(value.location()),
|
location: span.union(value.location()),
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
|
@ -1062,7 +891,7 @@ pub fn expr_parser(
|
||||||
let product = unary
|
let product = unary
|
||||||
.clone()
|
.clone()
|
||||||
.then(op.then(unary).repeated())
|
.then(op.then(unary).repeated())
|
||||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||||
location: a.location().union(b.location()),
|
location: a.location().union(b.location()),
|
||||||
name: op,
|
name: op,
|
||||||
left: Box::new(a),
|
left: Box::new(a),
|
||||||
|
@ -1079,7 +908,7 @@ pub fn expr_parser(
|
||||||
let sum = product
|
let sum = product
|
||||||
.clone()
|
.clone()
|
||||||
.then(op.then(product).repeated())
|
.then(op.then(product).repeated())
|
||||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||||
location: a.location().union(b.location()),
|
location: a.location().union(b.location()),
|
||||||
name: op,
|
name: op,
|
||||||
left: Box::new(a),
|
left: Box::new(a),
|
||||||
|
@ -1100,7 +929,7 @@ pub fn expr_parser(
|
||||||
let comparison = sum
|
let comparison = sum
|
||||||
.clone()
|
.clone()
|
||||||
.then(op.then(sum).repeated())
|
.then(op.then(sum).repeated())
|
||||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||||
location: a.location().union(b.location()),
|
location: a.location().union(b.location()),
|
||||||
name: op,
|
name: op,
|
||||||
left: Box::new(a),
|
left: Box::new(a),
|
||||||
|
@ -1113,7 +942,7 @@ pub fn expr_parser(
|
||||||
let conjunction = comparison
|
let conjunction = comparison
|
||||||
.clone()
|
.clone()
|
||||||
.then(op.then(comparison).repeated())
|
.then(op.then(comparison).repeated())
|
||||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||||
location: a.location().union(b.location()),
|
location: a.location().union(b.location()),
|
||||||
name: op,
|
name: op,
|
||||||
left: Box::new(a),
|
left: Box::new(a),
|
||||||
|
@ -1126,7 +955,7 @@ pub fn expr_parser(
|
||||||
let disjunction = conjunction
|
let disjunction = conjunction
|
||||||
.clone()
|
.clone()
|
||||||
.then(op.then(conjunction).repeated())
|
.then(op.then(conjunction).repeated())
|
||||||
.foldl(|a, (op, b)| expr::UntypedExpr::BinOp {
|
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||||
location: a.location().union(b.location()),
|
location: a.location().union(b.location()),
|
||||||
name: op,
|
name: op,
|
||||||
left: Box::new(a),
|
left: Box::new(a),
|
||||||
|
@ -1143,13 +972,13 @@ pub fn expr_parser(
|
||||||
.repeated(),
|
.repeated(),
|
||||||
)
|
)
|
||||||
.foldl(|l, (pipe, r)| {
|
.foldl(|l, (pipe, r)| {
|
||||||
if let expr::UntypedExpr::PipeLine {
|
if let UntypedExpr::PipeLine {
|
||||||
mut expressions,
|
mut expressions,
|
||||||
one_liner,
|
one_liner,
|
||||||
} = l
|
} = l
|
||||||
{
|
{
|
||||||
expressions.push(r);
|
expressions.push(r);
|
||||||
return expr::UntypedExpr::PipeLine {
|
return UntypedExpr::PipeLine {
|
||||||
expressions,
|
expressions,
|
||||||
one_liner,
|
one_liner,
|
||||||
};
|
};
|
||||||
|
@ -1157,7 +986,7 @@ pub fn expr_parser(
|
||||||
|
|
||||||
let mut expressions = Vec1::new(l);
|
let mut expressions = Vec1::new(l);
|
||||||
expressions.push(r);
|
expressions.push(r);
|
||||||
expr::UntypedExpr::PipeLine {
|
UntypedExpr::PipeLine {
|
||||||
expressions,
|
expressions,
|
||||||
one_liner: pipe != Token::NewLinePipe,
|
one_liner: pipe != Token::NewLinePipe,
|
||||||
}
|
}
|
||||||
|
@ -1177,7 +1006,7 @@ pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Er
|
||||||
location: span,
|
location: span,
|
||||||
});
|
});
|
||||||
|
|
||||||
let constant_parser = constant_value_parser().map(ast::ClauseGuard::Constant);
|
let constant_parser = definitions::constant::value().map(ast::ClauseGuard::Constant);
|
||||||
|
|
||||||
let block_parser = r
|
let block_parser = r
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -1281,122 +1110,6 @@ pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Er
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
|
||||||
recursive(|r| {
|
|
||||||
choice((
|
|
||||||
// Type hole
|
|
||||||
select! {Token::DiscardName { name } => name}.map_with_span(|name, span| {
|
|
||||||
ast::Annotation::Hole {
|
|
||||||
location: span,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
// Tuple
|
|
||||||
r.clone()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.at_least(2)
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(
|
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
|
||||||
just(Token::RightParen),
|
|
||||||
)
|
|
||||||
.map_with_span(|elems, span| ast::Annotation::Tuple {
|
|
||||||
location: span,
|
|
||||||
elems,
|
|
||||||
}),
|
|
||||||
// Function
|
|
||||||
just(Token::Fn)
|
|
||||||
.ignore_then(
|
|
||||||
r.clone()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
|
||||||
)
|
|
||||||
.then_ignore(just(Token::RArrow))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(|(arguments, ret), span| ast::Annotation::Fn {
|
|
||||||
location: span,
|
|
||||||
arguments,
|
|
||||||
ret: Box::new(ret),
|
|
||||||
}),
|
|
||||||
// Constructor function
|
|
||||||
select! {Token::UpName { name } => name}
|
|
||||||
.then(
|
|
||||||
r.clone()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::Less), just(Token::Greater))
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.map_with_span(|(name, arguments), span| ast::Annotation::Constructor {
|
|
||||||
location: span,
|
|
||||||
module: None,
|
|
||||||
name,
|
|
||||||
arguments: arguments.unwrap_or_default(),
|
|
||||||
}),
|
|
||||||
// Constructor Module or type Variable
|
|
||||||
select! {Token::Name { name } => name}
|
|
||||||
.then(
|
|
||||||
just(Token::Dot)
|
|
||||||
.ignore_then(select! {Token::UpName {name} => name})
|
|
||||||
.then(
|
|
||||||
r.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::Less), just(Token::Greater))
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.map_with_span(|(mod_name, opt_dot), span| {
|
|
||||||
if let Some((name, arguments)) = opt_dot {
|
|
||||||
ast::Annotation::Constructor {
|
|
||||||
location: span,
|
|
||||||
module: Some(mod_name),
|
|
||||||
name,
|
|
||||||
arguments: arguments.unwrap_or_default(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: parse_error(ParseErrorType::NotConstType, SrcSpan { start, end })
|
|
||||||
ast::Annotation::Var {
|
|
||||||
location: span,
|
|
||||||
name: mod_name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn labeled_constructor_type_args(
|
|
||||||
) -> impl Parser<Token, Vec<ast::RecordConstructorArg<()>>, Error = ParseError> {
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.then_ignore(just(Token::Colon))
|
|
||||||
.then(type_parser())
|
|
||||||
.map_with_span(|(name, annotation), span| ast::RecordConstructorArg {
|
|
||||||
label: Some(name),
|
|
||||||
annotation,
|
|
||||||
tipo: (),
|
|
||||||
doc: None,
|
|
||||||
location: span,
|
|
||||||
})
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_name_with_args() -> impl Parser<Token, (String, Option<Vec<String>>), Error = ParseError>
|
|
||||||
{
|
|
||||||
just(Token::Type).ignore_then(
|
|
||||||
select! {Token::UpName { name } => name}.then(
|
|
||||||
select! {Token::Name { name } => name}
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::Less), just(Token::Greater))
|
|
||||||
.or_not(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
||||||
recursive(|r| {
|
recursive(|r| {
|
||||||
let record_constructor_pattern_arg_parser = choice((
|
let record_constructor_pattern_arg_parser = choice((
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::ast;
|
||||||
|
|
||||||
|
use super::{error::ParseError, token::Token};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
||||||
|
recursive(|r| {
|
||||||
|
choice((
|
||||||
|
// Type hole
|
||||||
|
select! {Token::DiscardName { name } => name}.map_with_span(|name, span| {
|
||||||
|
ast::Annotation::Hole {
|
||||||
|
location: span,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// Tuple
|
||||||
|
r.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.at_least(2)
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(
|
||||||
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
|
just(Token::RightParen),
|
||||||
|
)
|
||||||
|
.map_with_span(|elems, span| ast::Annotation::Tuple {
|
||||||
|
location: span,
|
||||||
|
elems,
|
||||||
|
}),
|
||||||
|
// Function
|
||||||
|
just(Token::Fn)
|
||||||
|
.ignore_then(
|
||||||
|
r.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||||
|
)
|
||||||
|
.then_ignore(just(Token::RArrow))
|
||||||
|
.then(r.clone())
|
||||||
|
.map_with_span(|(arguments, ret), span| ast::Annotation::Fn {
|
||||||
|
location: span,
|
||||||
|
arguments,
|
||||||
|
ret: Box::new(ret),
|
||||||
|
}),
|
||||||
|
// Constructor function
|
||||||
|
select! {Token::UpName { name } => name}
|
||||||
|
.then(
|
||||||
|
r.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::Less), just(Token::Greater))
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map_with_span(|(name, arguments), span| ast::Annotation::Constructor {
|
||||||
|
location: span,
|
||||||
|
module: None,
|
||||||
|
name,
|
||||||
|
arguments: arguments.unwrap_or_default(),
|
||||||
|
}),
|
||||||
|
// Constructor Module or type Variable
|
||||||
|
select! {Token::Name { name } => name}
|
||||||
|
.then(
|
||||||
|
just(Token::Dot)
|
||||||
|
.ignore_then(select! {Token::UpName {name} => name})
|
||||||
|
.then(
|
||||||
|
r.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::Less), just(Token::Greater))
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map_with_span(|(mod_name, opt_dot), span| {
|
||||||
|
if let Some((name, arguments)) = opt_dot {
|
||||||
|
ast::Annotation::Constructor {
|
||||||
|
location: span,
|
||||||
|
module: Some(mod_name),
|
||||||
|
name,
|
||||||
|
arguments: arguments.unwrap_or_default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: parse_error(ParseErrorType::NotConstType, SrcSpan { start, end })
|
||||||
|
ast::Annotation::Var {
|
||||||
|
location: span,
|
||||||
|
name: mod_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
parser::{error::ParseError, token::Token, utils},
|
parser::{annotation, error::ParseError, token::Token, utils},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
|
@ -10,9 +10,13 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
.or_not()
|
.or_not()
|
||||||
.then_ignore(just(Token::Const))
|
.then_ignore(just(Token::Const))
|
||||||
.then(select! {Token::Name{name} => name})
|
.then(select! {Token::Name{name} => name})
|
||||||
.then(just(Token::Colon).ignore_then(type_parser()).or_not())
|
.then(
|
||||||
|
just(Token::Colon)
|
||||||
|
.ignore_then(annotation::parser())
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
.then_ignore(just(Token::Equal))
|
.then_ignore(just(Token::Equal))
|
||||||
.then(constant_value_parser())
|
.then(value())
|
||||||
.map_with_span(|(((public, name), annotation), value), span| {
|
.map_with_span(|(((public, name), annotation), value), span| {
|
||||||
ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant {
|
ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant {
|
||||||
doc: None,
|
doc: None,
|
||||||
|
@ -25,3 +29,37 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value() -> impl Parser<Token, ast::Constant, Error = ParseError> {
|
||||||
|
let constant_string_parser =
|
||||||
|
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||||
|
ast::Constant::String {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let constant_int_parser =
|
||||||
|
select! {Token::Int {value, base} => (value, base)}.map_with_span(|(value, base), span| {
|
||||||
|
ast::Constant::Int {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
base,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let constant_bytearray_parser =
|
||||||
|
utils::bytearray().map_with_span(|(preferred_format, bytes), span| {
|
||||||
|
ast::Constant::ByteArray {
|
||||||
|
location: span,
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
choice((
|
||||||
|
constant_string_parser,
|
||||||
|
constant_int_parser,
|
||||||
|
constant_bytearray_parser,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
parser::{error::ParseError, token::Token, utils},
|
parser::{annotation, error::ParseError, token::Token, utils},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
let unlabeled_constructor_type_args = type_parser()
|
let unlabeled_constructor_type_args = annotation()
|
||||||
.map_with_span(|annotation, span| ast::RecordConstructorArg {
|
.map_with_span(|annotation, span| ast::RecordConstructorArg {
|
||||||
label: None,
|
label: None,
|
||||||
annotation,
|
annotation,
|
||||||
|
@ -49,7 +49,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
utils::public()
|
utils::public()
|
||||||
.then(just(Token::Opaque).ignored().or_not())
|
.then(just(Token::Opaque).ignored().or_not())
|
||||||
.or_not()
|
.or_not()
|
||||||
.then(type_name_with_args())
|
.then(utils::type_name_with_args())
|
||||||
.then(choice((constructors, record_sugar)))
|
.then(choice((constructors, record_sugar)))
|
||||||
.map_with_span(|((pub_opaque, (name, parameters)), constructors), span| {
|
.map_with_span(|((pub_opaque, (name, parameters)), constructors), span| {
|
||||||
ast::UntypedDefinition::DataType(ast::DataType {
|
ast::UntypedDefinition::DataType(ast::DataType {
|
||||||
|
@ -75,3 +75,20 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn labeled_constructor_type_args(
|
||||||
|
) -> impl Parser<Token, Vec<ast::RecordConstructorArg<()>>, Error = ParseError> {
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(annotation())
|
||||||
|
.map_with_span(|(name, annotation), span| ast::RecordConstructorArg {
|
||||||
|
label: Some(name),
|
||||||
|
annotation,
|
||||||
|
tipo: (),
|
||||||
|
doc: None,
|
||||||
|
location: span,
|
||||||
|
})
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast, expr,
|
ast,
|
||||||
parser::{error::ParseError, token::Token, utils},
|
expr::UntypedExpr,
|
||||||
|
parser::{annotation, error::ParseError, expr, token::Token, utils},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
|
@ -11,15 +12,15 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
.then_ignore(just(Token::Fn))
|
.then_ignore(just(Token::Fn))
|
||||||
.then(select! {Token::Name {name} => name})
|
.then(select! {Token::Name {name} => name})
|
||||||
.then(
|
.then(
|
||||||
fn_param_parser(false)
|
param(false)
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||||
.map_with_span(|arguments, span| (arguments, span)),
|
.map_with_span(|arguments, span| (arguments, span)),
|
||||||
)
|
)
|
||||||
.then(just(Token::RArrow).ignore_then(type_parser()).or_not())
|
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
||||||
.then(
|
.then(
|
||||||
expr_seq_parser()
|
expr::sequence()
|
||||||
.or_not()
|
.or_not()
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||||
)
|
)
|
||||||
|
@ -27,7 +28,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
|((((opt_pub, name), (arguments, args_span)), return_annotation), body), span| {
|
|((((opt_pub, name), (arguments, args_span)), return_annotation), body), span| {
|
||||||
ast::UntypedDefinition::Fn(ast::Function {
|
ast::UntypedDefinition::Fn(ast::Function {
|
||||||
arguments,
|
arguments,
|
||||||
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
|
body: body.unwrap_or_else(|| UntypedExpr::todo(span, None)),
|
||||||
doc: None,
|
doc: None,
|
||||||
location: ast::Span {
|
location: ast::Span {
|
||||||
start: span.start,
|
start: span.start,
|
||||||
|
@ -46,3 +47,43 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||||
|
choice((
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.then(select! {Token::DiscardName {name} => name})
|
||||||
|
.map_with_span(|(label, name), span| ast::ArgName::Discarded {
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
}),
|
||||||
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::ArgName::Discarded {
|
||||||
|
label: name.clone(),
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.then(select! {Token::Name {name} => name})
|
||||||
|
.map_with_span(move |(label, name), span| ast::ArgName::Named {
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
is_validator_param,
|
||||||
|
}),
|
||||||
|
select! {Token::Name {name} => name}.map_with_span(move |name, span| ast::ArgName::Named {
|
||||||
|
label: name.clone(),
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
is_validator_param,
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
|
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||||
|
location: span,
|
||||||
|
annotation,
|
||||||
|
tipo: (),
|
||||||
|
arg_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
mod constant;
|
pub mod constant;
|
||||||
mod data_type;
|
mod data_type;
|
||||||
mod function;
|
mod function;
|
||||||
mod import;
|
mod import;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast, expr,
|
ast,
|
||||||
parser::{error::ParseError, token::Token},
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, expr, token::Token},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
|
@ -15,14 +16,14 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
.then_ignore(just(Token::RightParen))
|
.then_ignore(just(Token::RightParen))
|
||||||
.map_with_span(|name, span| (name, span))
|
.map_with_span(|name, span| (name, span))
|
||||||
.then(
|
.then(
|
||||||
expr_seq_parser()
|
expr::sequence()
|
||||||
.or_not()
|
.or_not()
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||||
)
|
)
|
||||||
.map_with_span(|(((fail, name), span_end), body), span| {
|
.map_with_span(|(((fail, name), span_end), body), span| {
|
||||||
ast::UntypedDefinition::Test(ast::Function {
|
ast::UntypedDefinition::Test(ast::Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
|
body: body.unwrap_or_else(|| UntypedExpr::todo(span, None)),
|
||||||
doc: None,
|
doc: None,
|
||||||
location: span_end,
|
location: span_end,
|
||||||
end_position: span.end - 1,
|
end_position: span.end - 1,
|
||||||
|
|
|
@ -2,15 +2,15 @@ use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
parser::{error::ParseError, token::Token, utils},
|
parser::{annotation, error::ParseError, token::Token, utils},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
utils::public()
|
utils::public()
|
||||||
.or_not()
|
.or_not()
|
||||||
.then(type_name_with_args())
|
.then(utils::type_name_with_args())
|
||||||
.then_ignore(just(Token::Equal))
|
.then_ignore(just(Token::Equal))
|
||||||
.then(type_parser())
|
.then(annotation())
|
||||||
.map_with_span(|((opt_pub, (alias, parameters)), annotation), span| {
|
.map_with_span(|((opt_pub, (alias, parameters)), annotation), span| {
|
||||||
ast::UntypedDefinition::TypeAlias(ast::TypeAlias {
|
ast::UntypedDefinition::TypeAlias(ast::TypeAlias {
|
||||||
alias,
|
alias,
|
||||||
|
|
|
@ -5,10 +5,12 @@ use crate::{
|
||||||
parser::{error::ParseError, token::Token},
|
parser::{error::ParseError, token::Token},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::function;
|
||||||
|
|
||||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||||
just(Token::Validator)
|
just(Token::Validator)
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
fn_param_parser(true)
|
function::param(true)
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||||
|
@ -16,7 +18,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
super::function()
|
function()
|
||||||
.repeated()
|
.repeated()
|
||||||
.at_least(1)
|
.at_least(1)
|
||||||
.at_most(2)
|
.at_most(2)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod sequence;
|
||||||
|
|
||||||
|
pub use sequence::parser as sequence;
|
|
@ -0,0 +1,36 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast::TraceKind,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||||
|
recursive(|r| {
|
||||||
|
choice((
|
||||||
|
just(Token::Trace)
|
||||||
|
.ignore_then(expr_parser(r.clone()))
|
||||||
|
.then(r.clone())
|
||||||
|
.map_with_span(|(text, then_), span| UntypedExpr::Trace {
|
||||||
|
kind: TraceKind::Trace,
|
||||||
|
location: span,
|
||||||
|
then: Box::new(then_),
|
||||||
|
text: Box::new(flexible_string_literal(text)),
|
||||||
|
}),
|
||||||
|
just(Token::ErrorTerm)
|
||||||
|
.ignore_then(expr_parser(r.clone()).or_not())
|
||||||
|
.map_with_span(|reason, span| {
|
||||||
|
UntypedExpr::error(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
|
just(Token::Todo)
|
||||||
|
.ignore_then(expr_parser(r.clone()).or_not())
|
||||||
|
.map_with_span(|reason, span| {
|
||||||
|
UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
|
expr_parser(r.clone())
|
||||||
|
.then(r.repeated())
|
||||||
|
.foldl(|current, next| current.append_in_sequence(next)),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,7 +1,95 @@
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use super::{error::ParseError, token::Token};
|
use crate::ast;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
error::{self, ParseError},
|
||||||
|
token::{Base, Token},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn public() -> impl Parser<Token, (), Error = ParseError> {
|
pub fn public() -> impl Parser<Token, (), Error = ParseError> {
|
||||||
just(Token::Pub).ignored()
|
just(Token::Pub).ignored()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bytearray(
|
||||||
|
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
|
||||||
|
let bytearray_list_parser = just(Token::Hash)
|
||||||
|
.ignore_then(
|
||||||
|
select! {Token::Int {value, base, ..} => (value, base)}
|
||||||
|
.validate(|(value, base), span, emit| {
|
||||||
|
let byte: u8 = match value.parse() {
|
||||||
|
Ok(b) => b,
|
||||||
|
Err(_) => {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Byte),
|
||||||
|
));
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(byte, base)
|
||||||
|
})
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
|
||||||
|
)
|
||||||
|
.validate(|bytes, span, emit| {
|
||||||
|
let base = bytes.iter().fold(Ok(None), |acc, (_, base)| match acc {
|
||||||
|
Ok(None) => Ok(Some(base)),
|
||||||
|
Ok(Some(previous_base)) if previous_base == base => Ok(Some(base)),
|
||||||
|
_ => Err(()),
|
||||||
|
});
|
||||||
|
|
||||||
|
let base = match base {
|
||||||
|
Err(()) => {
|
||||||
|
emit(ParseError::hybrid_notation_in_bytearray(span));
|
||||||
|
Base::Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => Base::Decimal {
|
||||||
|
numeric_underscore: false,
|
||||||
|
},
|
||||||
|
Ok(Some(base)) => *base,
|
||||||
|
};
|
||||||
|
|
||||||
|
(bytes.into_iter().map(|(b, _)| b).collect::<Vec<u8>>(), base)
|
||||||
|
})
|
||||||
|
.map(|(bytes, base)| (ast::ByteArrayFormatPreference::ArrayOfBytes(base), bytes));
|
||||||
|
|
||||||
|
let bytearray_hexstring_parser =
|
||||||
|
just(Token::Hash)
|
||||||
|
.ignore_then(select! {Token::ByteString {value} => value}.validate(
|
||||||
|
|value, span, emit| match hex::decode(value) {
|
||||||
|
Ok(bytes) => bytes,
|
||||||
|
Err(_) => {
|
||||||
|
emit(ParseError::malformed_base16_string_literal(span));
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.map(|token| (ast::ByteArrayFormatPreference::HexadecimalString, token));
|
||||||
|
|
||||||
|
let bytearray_utf8_parser = select! {Token::ByteString {value} => value.into_bytes() }
|
||||||
|
.map(|token| (ast::ByteArrayFormatPreference::Utf8String, token));
|
||||||
|
|
||||||
|
choice((
|
||||||
|
bytearray_list_parser,
|
||||||
|
bytearray_hexstring_parser,
|
||||||
|
bytearray_utf8_parser,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_name_with_args() -> impl Parser<Token, (String, Option<Vec<String>>), Error = ParseError>
|
||||||
|
{
|
||||||
|
just(Token::Type).ignore_then(
|
||||||
|
select! {Token::UpName { name } => name}.then(
|
||||||
|
select! {Token::Name { name } => name}
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::Less), just(Token::Greater))
|
||||||
|
.or_not(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue