149 lines
4.7 KiB
Rust
149 lines
4.7 KiB
Rust
use chumsky::prelude::*;
|
|
|
|
use crate::{ast, error::ParseError, token::Token};
|
|
|
|
pub fn module_parser(
|
|
kind: ast::ModuleKind,
|
|
) -> impl Parser<Token, ast::UntypedModule, Error = ParseError> {
|
|
let unqualified_import = choice((
|
|
select! {Token::Name { name } => name}.then(
|
|
just(Token::As)
|
|
.ignore_then(select! {Token::Name { name } => name})
|
|
.or_not(),
|
|
),
|
|
select! {Token::UpName { name } => name}.then(
|
|
just(Token::As)
|
|
.ignore_then(select! {Token::UpName { name } => name})
|
|
.or_not(),
|
|
),
|
|
))
|
|
.map_with_span(|(name, as_name), span| ast::UnqualifiedImport {
|
|
name,
|
|
location: span,
|
|
as_name,
|
|
layer: Default::default(),
|
|
});
|
|
|
|
let unqualified_imports = just(Token::Dot)
|
|
.ignore_then(
|
|
unqualified_import
|
|
.separated_by(just(Token::Comma))
|
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
|
)
|
|
.or_not();
|
|
|
|
let as_name = just(Token::As)
|
|
.ignore_then(select! {Token::Name { name } => name})
|
|
.or_not();
|
|
|
|
let module_path = select! {Token::Name { name } => name}
|
|
.separated_by(just(Token::Slash))
|
|
.then(unqualified_imports)
|
|
.then(as_name);
|
|
|
|
let import = just(Token::Use).ignore_then(module_path).map_with_span(
|
|
|((module, unqualified), as_name), span| ast::UntypedDefinition::Use {
|
|
module,
|
|
as_name,
|
|
unqualified: unqualified.unwrap_or_default(),
|
|
package: (),
|
|
location: span,
|
|
},
|
|
);
|
|
|
|
choice((import,))
|
|
.repeated()
|
|
.then_ignore(end())
|
|
.map(move |definitions| ast::UntypedModule {
|
|
kind,
|
|
definitions,
|
|
docs: vec![],
|
|
name: vec![],
|
|
type_info: (),
|
|
})
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use chumsky::prelude::*;
|
|
|
|
use crate::{
|
|
ast::{self, Span, SrcId},
|
|
lexer,
|
|
parser::module_parser,
|
|
};
|
|
|
|
#[test]
|
|
fn simple() {
|
|
let code = r#"
|
|
use std/list
|
|
use std/address.{Address as A, thing as w}
|
|
use std/tx as t
|
|
"#;
|
|
let len = code.chars().count();
|
|
|
|
let span = |i| Span::new(SrcId::empty(), i..i + 1);
|
|
|
|
let tokens = lexer::lexer()
|
|
.parse(chumsky::Stream::from_iter(
|
|
span(len),
|
|
code.chars().enumerate().map(|(i, c)| (c, span(i))),
|
|
))
|
|
.unwrap();
|
|
|
|
dbg!(tokens.clone());
|
|
|
|
let res = module_parser(ast::ModuleKind::Script)
|
|
.parse(chumsky::Stream::from_iter(span(len), tokens.into_iter()))
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
res,
|
|
ast::UntypedModule {
|
|
docs: vec![],
|
|
kind: ast::ModuleKind::Script,
|
|
name: vec![],
|
|
type_info: (),
|
|
definitions: vec![
|
|
ast::UntypedDefinition::Use {
|
|
location: Span::new(SrcId::empty(), 13..25),
|
|
module: vec!["std".to_string(), "list".to_string()],
|
|
as_name: None,
|
|
unqualified: vec![],
|
|
package: (),
|
|
},
|
|
ast::UntypedDefinition::Use {
|
|
location: Span::new(SrcId::empty(), 38..80),
|
|
module: vec!["std".to_string(), "address".to_string()],
|
|
as_name: None,
|
|
unqualified: vec![
|
|
ast::UnqualifiedImport {
|
|
as_name: Some("A".to_string()),
|
|
location: Span::new(SrcId::empty(), 55..67),
|
|
layer: Default::default(),
|
|
name: "Address".to_string()
|
|
},
|
|
ast::UnqualifiedImport {
|
|
as_name: Some("w".to_string()),
|
|
location: Span::new(SrcId::empty(), 69..79),
|
|
layer: Default::default(),
|
|
name: "thing".to_string()
|
|
}
|
|
],
|
|
package: (),
|
|
},
|
|
ast::UntypedDefinition::Use {
|
|
location: Span::new(SrcId::empty(), 93..108),
|
|
module: vec!["std".to_string(), "tx".to_string()],
|
|
as_name: Some("t".to_string()),
|
|
unqualified: vec![],
|
|
package: (),
|
|
}
|
|
]
|
|
},
|
|
"{:#?}",
|
|
res,
|
|
);
|
|
}
|
|
}
|