1use super::{expr::Expr, parse_token, DocComment, ExternName, Lookahead, Parse, ParseResult, Peek};
2use crate::lexer::{Lexer, Token};
3use miette::SourceSpan;
4use serde::Serialize;
5
6#[derive(Debug, Clone, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct ExportStatement<'a> {
10 pub docs: Vec<DocComment<'a>>,
12 pub expr: Expr<'a>,
14 pub options: ExportOptions<'a>,
16}
17
18impl<'a> Parse<'a> for ExportStatement<'a> {
19 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
20 let docs = Parse::parse(lexer)?;
21 parse_token(lexer, Token::ExportKeyword)?;
22 let expr = Parse::parse(lexer)?;
23 let options = Parse::parse(lexer)?;
24 parse_token(lexer, Token::Semicolon)?;
25 Ok(Self {
26 docs,
27 expr,
28 options,
29 })
30 }
31}
32
33impl Peek for ExportStatement<'_> {
34 fn peek(lookahead: &mut Lookahead) -> bool {
35 lookahead.peek(Token::ExportKeyword)
36 }
37}
38
39#[derive(Debug, Clone, Serialize)]
41#[serde(rename_all = "camelCase")]
42pub enum ExportOptions<'a> {
43 None,
45 Spread(SourceSpan),
47 Rename(ExternName<'a>),
49}
50
51impl<'a> Parse<'a> for ExportOptions<'a> {
52 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
53 if let Some((Ok(Token::Ellipsis), _)) = lexer.peek() {
54 let span = parse_token(lexer, Token::Ellipsis)?;
56 return Ok(Self::Spread(span));
57 }
58
59 if let Some((Ok(Token::AsKeyword), _)) = lexer.peek() {
60 parse_token(lexer, Token::AsKeyword)?;
62 return Ok(Self::Rename(Parse::parse(lexer)?));
63 }
64
65 Ok(Self::None)
66 }
67}
68
69#[cfg(test)]
70mod test {
71 use crate::ast::test::roundtrip;
72
73 #[test]
74 fn export_statement_roundtrip() {
75 roundtrip(
76 "package foo:bar; export y;",
77 "package foo:bar;\n\nexport y;\n",
78 )
79 .unwrap();
80 roundtrip(
81 "package foo:bar; export foo.%with as \"foo\";",
82 "package foo:bar;\n\nexport foo.%with as \"foo\";\n",
83 )
84 .unwrap();
85 roundtrip(
86 "package foo:bar; export y.x.z;",
87 "package foo:bar;\n\nexport y.x.z;\n",
88 )
89 .unwrap();
90 roundtrip(
91 "package foo:bar; export y.x.z as \"baz\";",
92 "package foo:bar;\n\nexport y.x.z as \"baz\";\n",
93 )
94 .unwrap();
95 roundtrip(
96 "package foo:bar; export y[\"x\"][\"z\"];",
97 "package foo:bar;\n\nexport y[\"x\"][\"z\"];\n",
98 )
99 .unwrap();
100 roundtrip(
101 "package foo:bar; export y[\"x\"][\"z\"] as \"x\";",
102 "package foo:bar;\n\nexport y[\"x\"][\"z\"] as \"x\";\n",
103 )
104 .unwrap();
105 roundtrip(
106 "package foo:bar; export foo[\"bar\"].baz[\"qux\"];",
107 "package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"];\n",
108 )
109 .unwrap();
110 roundtrip(
111 "package foo:bar; export foo[\"bar\"].baz[\"qux\"] as \"qux\";",
112 "package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"] as \"qux\";\n",
113 )
114 .unwrap();
115
116 roundtrip(
117 "package foo:bar; export (y);",
118 "package foo:bar;\n\nexport (y);\n",
119 )
120 .unwrap();
121
122 roundtrip(
123 "package foo:bar; export new foo:bar {};",
124 "package foo:bar;\n\nexport new foo:bar {};\n",
125 )
126 .unwrap();
127
128 roundtrip(
129 "package foo:bar; export new foo:bar {} /* foo */ as \"foo\";",
130 "package foo:bar;\n\nexport new foo:bar {} as \"foo\";\n",
131 )
132 .unwrap();
133
134 roundtrip(
135 "package foo:bar; export new foo:bar { foo, \"bar\": (new baz:qux {a, ...}), \"baz\": foo[\"baz\"].qux };",
136 "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",
137 )
138 .unwrap();
139
140 roundtrip(
141 "package foo:bar; export i...;",
142 "package foo:bar;\n\nexport i...;\n",
143 )
144 .unwrap();
145 }
146}