1use crate::*;
2
3
4mod directive;
5
6mod directive_addr;
7pub use directive_addr::AstDirectiveAddr;
8
9mod directive_align;
10pub use directive_align::AstDirectiveAlign;
11
12mod directive_assert;
13pub use directive_assert::AstDirectiveAssert;
14
15mod directive_bank;
16pub use directive_bank::AstDirectiveBank;
17
18mod directive_bankdef;
19pub use directive_bankdef::AstDirectiveBankdef;
20
21mod directive_bits;
22pub use directive_bits::AstDirectiveBits;
23
24mod directive_const;
25
26mod directive_data;
27pub use directive_data::AstDirectiveData;
28
29mod directive_fn;
30pub use directive_fn::{
31 AstDirectiveFn,
32 AstFnParameter,
33};
34
35mod directive_if;
36pub use directive_if::AstDirectiveIf;
37
38mod directive_include;
39pub use directive_include::AstDirectiveInclude;
40
41mod directive_labelalign;
42pub use directive_labelalign::AstDirectiveLabelAlign;
43
44mod directive_noemit;
45pub use directive_noemit::AstDirectiveNoEmit;
46
47mod directive_once;
48pub use directive_once::AstDirectiveOnce;
49
50mod directive_res;
51pub use directive_res::AstDirectiveRes;
52
53mod directive_ruledef;
54pub use directive_ruledef::{
55 AstDirectiveRuledef,
56 AstRule,
57 AstRulePatternPart,
58 AstRuleParameter,
59 AstRuleParameterType,
60};
61
62mod fields;
63pub use fields::{
64 AstFields,
65 AstField,
66};
67
68mod instruction;
69pub use instruction::AstInstruction;
70
71mod symbol;
72pub use symbol::{
73 AstSymbol,
74 AstSymbolKind,
75 AstSymbolConstant,
76};
77
78
79#[derive(Clone, Debug)]
80pub enum AstAny
81{
82 DirectiveAddr(AstDirectiveAddr),
83 DirectiveAlign(AstDirectiveAlign),
84 DirectiveAssert(AstDirectiveAssert),
85 DirectiveBank(AstDirectiveBank),
86 DirectiveBankdef(AstDirectiveBankdef),
87 DirectiveBits(AstDirectiveBits),
88 DirectiveData(AstDirectiveData),
89 DirectiveFn(AstDirectiveFn),
90 DirectiveIf(AstDirectiveIf),
91 DirectiveInclude(AstDirectiveInclude),
92 DirectiveLabelAlign(AstDirectiveLabelAlign),
93 DirectiveNoEmit(AstDirectiveNoEmit),
94 DirectiveOnce(AstDirectiveOnce),
95 DirectiveRes(AstDirectiveRes),
96 DirectiveRuledef(AstDirectiveRuledef),
97 Instruction(AstInstruction),
98 Symbol(AstSymbol),
99}
100
101
102#[derive(Clone, Debug)]
103pub struct AstTopLevel
104{
105 pub nodes: Vec<AstAny>,
106}
107
108
109pub fn parse_many_and_resolve_includes<S>(
110 report: &mut diagn::Report,
111 fileserver: &mut dyn util::FileServer,
112 root_filenames: &[S])
113 -> Result<AstTopLevel, ()>
114 where S: std::borrow::Borrow<str>
115{
116 let mut result = AstTopLevel {
117 nodes: Vec::new(),
118 };
119
120 let mut once_filenames = std::collections::HashSet::new();
121
122 for file in root_filenames
123 {
124 let ast = parse_and_resolve_includes(
125 report,
126 None,
127 fileserver,
128 file.borrow(),
129 &mut Vec::new(),
130 &mut once_filenames)?;
131
132 result.nodes.extend(ast.nodes);
133 }
134
135 Ok(result)
136}
137
138
139pub fn parse_and_resolve_includes<S>(
140 report: &mut diagn::Report,
141 span: Option<diagn::Span>,
142 fileserver: &mut dyn util::FileServer,
143 root_filename: S,
144 seen_filenames: &mut Vec<String>,
145 once_filenames: &mut std::collections::HashSet<String>)
146 -> Result<AstTopLevel, ()>
147 where S: std::borrow::Borrow<str>
148{
149 if once_filenames.contains(root_filename.borrow())
150 {
151 return Ok(AstTopLevel {
152 nodes: Vec::new(),
153 });
154 }
155
156 let file_handle = fileserver.get_handle(
157 report,
158 span,
159 root_filename.borrow())?;
160
161 let src = fileserver.get_str(
162 report,
163 span,
164 file_handle)?;
165
166 let mut walker = syntax::Walker::new(
167 &src,
168 file_handle,
169 0);
170
171 let mut root_ast = parse(report, &mut walker)?;
172
173 if root_ast.nodes.iter().any(|n| matches!(n, AstAny::DirectiveOnce(_)))
175 {
176 once_filenames.insert(root_filename.borrow().to_owned());
177 }
178
179 let mut node_index = 0;
182 while node_index < root_ast.nodes.len()
183 {
184 let node = &root_ast.nodes[node_index];
185
186 if let AstAny::DirectiveInclude(ast_include) = node
187 {
188 let included_filename = util::filename_navigate(
189 report,
190 ast_include.filename_span,
191 root_filename.borrow(),
192 &ast_include.filename)?;
193
194
195 if seen_filenames.contains(&included_filename)
196 {
197 report.error_span(
198 "recursive file inclusion",
199 ast_include.filename_span);
200
201 return Err(());
202 }
203
204
205 seen_filenames.push(included_filename.clone());
206
207 let inner_ast = parse_and_resolve_includes(
208 report,
209 Some(ast_include.filename_span),
210 fileserver,
211 included_filename.as_ref(),
212 seen_filenames,
213 once_filenames)?;
214
215 let inner_ast_len = inner_ast.nodes.len();
216
217 root_ast.nodes.splice(
218 node_index..(node_index + 1),
219 inner_ast.nodes);
220
221 node_index += inner_ast_len;
224
225 seen_filenames.pop();
226 }
227 else
228 {
229 node_index += 1;
230 }
231 }
232
233 Ok(root_ast)
234}
235
236
237pub fn parse(
238 report: &mut diagn::Report,
239 walker: &mut syntax::Walker)
240 -> Result<AstTopLevel, ()>
241{
242 let mut nodes = Vec::new();
243
244 while !walker.is_over()
245 {
246 if let Some(node) = parse_line(report, walker)?
247 {
248 nodes.push(node);
249 }
250 }
251
252 Ok(AstTopLevel {
253 nodes
254 })
255}
256
257
258pub fn parse_nested_toplevel(
259 report: &mut diagn::Report,
260 walker: &mut syntax::Walker)
261 -> Result<AstTopLevel, ()>
262{
263 let mut nodes = Vec::new();
264
265 while !walker.is_over() &&
266 !walker.next_useful_is(0, syntax::TokenKind::BraceClose)
267 {
268 if let Some(node) = parse_line(report, walker)?
269 {
270 nodes.push(node);
271 }
272 }
273
274 Ok(AstTopLevel {
275 nodes
276 })
277}
278
279
280fn parse_line(
281 report: &mut diagn::Report,
282 walker: &mut syntax::Walker)
283 -> Result<Option<AstAny>, ()>
284{
285 if walker.next_useful_is(0, syntax::TokenKind::Hash)
287 {
288 Ok(Some(directive::parse(report, walker)?))
289 }
290
291 else if walker.next_useful_is(0, syntax::TokenKind::Identifier) &&
293 walker.next_useful_is(1, syntax::TokenKind::Colon)
294 {
295 Ok(Some(symbol::parse(report, walker)?))
296 }
297
298 else if walker.next_useful_is(0, syntax::TokenKind::Identifier) &&
300 walker.next_useful_is(1, syntax::TokenKind::Equal)
301 {
302 Ok(Some(symbol::parse(report, walker)?))
303 }
304
305 else if walker.next_useful_is(0, syntax::TokenKind::Dot)
307 {
308 Ok(Some(symbol::parse(report, walker)?))
309 }
310
311 else if walker.maybe_expect_linebreak().is_some()
313 {
314 Ok(None)
315 }
316
317 else
319 {
320 Ok(Some(AstAny::Instruction(
321 instruction::parse(report, walker)?)))
322 }
323}
324
325
326impl AstAny
327{
328 pub fn span(&self) -> diagn::Span
329 {
330 match self
331 {
332 AstAny::DirectiveAddr(node) => node.header_span,
333 AstAny::DirectiveAlign(node) => node.header_span,
334 AstAny::DirectiveAssert(node) => node.header_span,
335 AstAny::DirectiveBank(node) => node.header_span,
336 AstAny::DirectiveBankdef(node) => node.header_span,
337 AstAny::DirectiveBits(node) => node.header_span,
338 AstAny::DirectiveData(node) => node.header_span,
339 AstAny::DirectiveFn(node) => node.header_span,
340 AstAny::DirectiveIf(node) => node.header_span,
341 AstAny::DirectiveInclude(node) => node.header_span,
342 AstAny::DirectiveLabelAlign(node) => node.header_span,
343 AstAny::DirectiveNoEmit(node) => node.header_span,
344 AstAny::DirectiveOnce(node) => node.header_span,
345 AstAny::DirectiveRes(node) => node.header_span,
346 AstAny::DirectiveRuledef(node) => node.header_span,
347 AstAny::Instruction(node) => node.span,
348 AstAny::Symbol(node) => node.decl_span,
349 }
350 }
351}