feat: finish moving definitions and start exprs
This commit is contained in:
91
crates/aiken-lang/src/parser/annotation.rs
Normal file
91
crates/aiken-lang/src/parser/annotation.rs
Normal file
@@ -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::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token, utils},
|
||||
parser::{annotation, error::ParseError, token::Token, utils},
|
||||
};
|
||||
|
||||
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()
|
||||
.then_ignore(just(Token::Const))
|
||||
.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(constant_value_parser())
|
||||
.then(value())
|
||||
.map_with_span(|(((public, name), annotation), value), span| {
|
||||
ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant {
|
||||
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::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token, utils},
|
||||
parser::{annotation, error::ParseError, token::Token, utils},
|
||||
};
|
||||
|
||||
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 {
|
||||
label: None,
|
||||
annotation,
|
||||
@@ -49,7 +49,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||
utils::public()
|
||||
.then(just(Token::Opaque).ignored().or_not())
|
||||
.or_not()
|
||||
.then(type_name_with_args())
|
||||
.then(utils::type_name_with_args())
|
||||
.then(choice((constructors, record_sugar)))
|
||||
.map_with_span(|((pub_opaque, (name, parameters)), constructors), span| {
|
||||
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 crate::{
|
||||
ast, expr,
|
||||
parser::{error::ParseError, token::Token, utils},
|
||||
ast,
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, expr, token::Token, utils},
|
||||
};
|
||||
|
||||
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(select! {Token::Name {name} => name})
|
||||
.then(
|
||||
fn_param_parser(false)
|
||||
param(false)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.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(
|
||||
expr_seq_parser()
|
||||
expr::sequence()
|
||||
.or_not()
|
||||
.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| {
|
||||
ast::UntypedDefinition::Fn(ast::Function {
|
||||
arguments,
|
||||
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(span, None)),
|
||||
doc: None,
|
||||
location: ast::Span {
|
||||
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 function;
|
||||
mod import;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast, expr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
ast,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, expr, token::Token},
|
||||
};
|
||||
|
||||
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))
|
||||
.map_with_span(|name, span| (name, span))
|
||||
.then(
|
||||
expr_seq_parser()
|
||||
expr::sequence()
|
||||
.or_not()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|(((fail, name), span_end), body), span| {
|
||||
ast::UntypedDefinition::Test(ast::Function {
|
||||
arguments: vec![],
|
||||
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(span, None)),
|
||||
doc: None,
|
||||
location: span_end,
|
||||
end_position: span.end - 1,
|
||||
|
||||
@@ -2,15 +2,15 @@ use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token, utils},
|
||||
parser::{annotation, error::ParseError, token::Token, utils},
|
||||
};
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
utils::public()
|
||||
.or_not()
|
||||
.then(type_name_with_args())
|
||||
.then(utils::type_name_with_args())
|
||||
.then_ignore(just(Token::Equal))
|
||||
.then(type_parser())
|
||||
.then(annotation())
|
||||
.map_with_span(|((opt_pub, (alias, parameters)), annotation), span| {
|
||||
ast::UntypedDefinition::TypeAlias(ast::TypeAlias {
|
||||
alias,
|
||||
|
||||
@@ -5,10 +5,12 @@ use crate::{
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
|
||||
use super::function;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
just(Token::Validator)
|
||||
.ignore_then(
|
||||
fn_param_parser(true)
|
||||
function::param(true)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
@@ -16,7 +18,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
||||
.or_not(),
|
||||
)
|
||||
.then(
|
||||
super::function()
|
||||
function()
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.at_most(2)
|
||||
|
||||
3
crates/aiken-lang/src/parser/expr/mod.rs
Normal file
3
crates/aiken-lang/src/parser/expr/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod sequence;
|
||||
|
||||
pub use sequence::parser as sequence;
|
||||
36
crates/aiken-lang/src/parser/expr/sequence.rs
Normal file
36
crates/aiken-lang/src/parser/expr/sequence.rs
Normal file
@@ -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 super::{error::ParseError, token::Token};
|
||||
use crate::ast;
|
||||
|
||||
use super::{
|
||||
error::{self, ParseError},
|
||||
token::{Base, Token},
|
||||
};
|
||||
|
||||
pub fn public() -> impl Parser<Token, (), Error = ParseError> {
|
||||
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(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user