use super::{expr::Expr, parse_token, DocComment, ExternName, Lookahead, Parse, ParseResult, Peek};
use crate::lexer::{Lexer, Token};
use miette::SourceSpan;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ExportStatement<'a> {
pub docs: Vec<DocComment<'a>>,
pub expr: Expr<'a>,
pub options: ExportOptions<'a>,
}
impl<'a> Parse<'a> for ExportStatement<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::ExportKeyword)?;
let expr = Parse::parse(lexer)?;
let options = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self {
docs,
expr,
options,
})
}
}
impl Peek for ExportStatement<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::ExportKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ExportOptions<'a> {
None,
Spread(SourceSpan),
Rename(ExternName<'a>),
}
impl<'a> Parse<'a> for ExportOptions<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
if let Some((Ok(Token::Ellipsis), _)) = lexer.peek() {
let span = parse_token(lexer, Token::Ellipsis)?;
return Ok(Self::Spread(span));
}
if let Some((Ok(Token::AsKeyword), _)) = lexer.peek() {
parse_token(lexer, Token::AsKeyword)?;
return Ok(Self::Rename(Parse::parse(lexer)?));
}
Ok(Self::None)
}
}
#[cfg(test)]
mod test {
use crate::ast::test::roundtrip;
#[test]
fn export_statement_roundtrip() {
roundtrip(
"package foo:bar; export y;",
"package foo:bar;\n\nexport y;\n",
)
.unwrap();
roundtrip(
"package foo:bar; export foo.%with as \"foo\";",
"package foo:bar;\n\nexport foo.%with as \"foo\";\n",
)
.unwrap();
roundtrip(
"package foo:bar; export y.x.z;",
"package foo:bar;\n\nexport y.x.z;\n",
)
.unwrap();
roundtrip(
"package foo:bar; export y.x.z as \"baz\";",
"package foo:bar;\n\nexport y.x.z as \"baz\";\n",
)
.unwrap();
roundtrip(
"package foo:bar; export y[\"x\"][\"z\"];",
"package foo:bar;\n\nexport y[\"x\"][\"z\"];\n",
)
.unwrap();
roundtrip(
"package foo:bar; export y[\"x\"][\"z\"] as \"x\";",
"package foo:bar;\n\nexport y[\"x\"][\"z\"] as \"x\";\n",
)
.unwrap();
roundtrip(
"package foo:bar; export foo[\"bar\"].baz[\"qux\"];",
"package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"];\n",
)
.unwrap();
roundtrip(
"package foo:bar; export foo[\"bar\"].baz[\"qux\"] as \"qux\";",
"package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"] as \"qux\";\n",
)
.unwrap();
roundtrip(
"package foo:bar; export (y);",
"package foo:bar;\n\nexport (y);\n",
)
.unwrap();
roundtrip(
"package foo:bar; export new foo:bar {};",
"package foo:bar;\n\nexport new foo:bar {};\n",
)
.unwrap();
roundtrip(
"package foo:bar; export new foo:bar {} /* foo */ as \"foo\";",
"package foo:bar;\n\nexport new foo:bar {} as \"foo\";\n",
)
.unwrap();
roundtrip(
"package foo:bar; export new foo:bar { foo, \"bar\": (new baz:qux {a, ...}), \"baz\": foo[\"baz\"].qux };",
"package foo:bar;\n\nexport new foo:bar {\n foo,\n \"bar\": (new baz:qux {\n a,\n ...\n }),\n \"baz\": foo[\"baz\"].qux,\n};\n",
)
.unwrap();
roundtrip(
"package foo:bar; export i...;",
"package foo:bar;\n\nexport i...;\n",
)
.unwrap();
}
}