calyx_frontend/
parser.rs

1#![allow(clippy::upper_case_acronyms)]
2
3//! Parser for Calyx programs.
4use super::Attributes;
5use super::ast::{
6    self, BitNum, Control, GuardComp as GC, GuardExpr, NumType,
7    StaticGuardExpr, Transition,
8};
9use crate::{
10    Attribute, Direction, PortDef, Primitive, Width,
11    attribute::SetAttribute,
12    attributes::ParseAttributeWrapper,
13    source_info::{
14        FileId as MetadataFileId, LineNum, PositionId, SourceInfoResult,
15        SourceInfoTable,
16    },
17};
18use calyx_utils::{self, CalyxResult, Id, PosString, float};
19use calyx_utils::{FileIdx, GPosIdx, GlobalPositionTable};
20use pest::pratt_parser::{Assoc, Op, PrattParser};
21use pest_consume::{Error, Parser, match_nodes};
22use std::io::Read;
23use std::path::Path;
24use std::str::FromStr;
25use std::{fs, path::PathBuf};
26
27type ParseResult<T> = Result<T, Error<Rule>>;
28type ComponentDef = ast::ComponentDef;
29
30/// Holds the results from parsing the `wires` section of a Calyx program.
31type ParsedConnections = (
32    Vec<ast::Wire>,
33    Vec<ast::Group>,
34    Vec<ast::StaticGroup>,
35    Vec<ast::Fsm>,
36);
37
38/// Data associated with parsing the file.
39#[derive(Clone)]
40struct UserData {
41    /// Index to the current file
42    pub file: FileIdx,
43}
44
45// user data is the input program so that we can create Id's
46// that have a reference to the input string
47type Node<'i> = pest_consume::Node<'i, Rule, UserData>;
48
49// include the grammar file so that Cargo knows to rebuild this file on grammar changes
50const _GRAMMAR: &str = include_str!("syntax.pest");
51
52// Define the precedence of binary operations. We use `lazy_static` so that
53// this is only ever constructed once.
54lazy_static::lazy_static! {
55    static ref PRATT: PrattParser<Rule> =
56    PrattParser::new()
57        .op(Op::infix(Rule::guard_or, Assoc::Left))
58        .op(Op::infix(Rule::guard_and, Assoc::Left));
59}
60
61#[derive(Parser)]
62#[grammar = "syntax.pest"]
63pub struct CalyxParser;
64
65impl CalyxParser {
66    /// Parse a Calyx program into an AST representation.
67    pub fn parse_file(path: &Path) -> CalyxResult<ast::NamespaceDef> {
68        let time = std::time::Instant::now();
69        let content = &fs::read(path).map_err(|err| {
70            calyx_utils::Error::invalid_file(format!(
71                "Failed to read {}: {err}",
72                path.to_string_lossy(),
73            ))
74        })?;
75        // Add a new file to the position table
76        let string_content = std::str::from_utf8(content)?.to_string();
77        let file = GlobalPositionTable::add_file(
78            path.to_string_lossy().to_string(),
79            string_content,
80        );
81        let user_data = UserData { file };
82
83        let content = GlobalPositionTable::get_source(file);
84
85        // Parse the file
86        let inputs =
87            CalyxParser::parse_with_userdata(Rule::file, content, user_data)
88                .map_err(|e| e.with_path(&path.to_string_lossy()))
89                .map_err(|e| {
90                    calyx_utils::Error::parse_error(e.variant.message())
91                        .with_pos(&Self::error_span(&e, file))
92                })?;
93        let input = inputs.single().map_err(|e| {
94            calyx_utils::Error::parse_error(e.variant.message())
95                .with_pos(&Self::error_span(&e, file))
96        })?;
97        let out = CalyxParser::file(input).map_err(|e| {
98            calyx_utils::Error::parse_error(e.variant.message())
99                .with_pos(&Self::error_span(&e, file))
100        })?;
101        log::info!(
102            "Parsed `{}` in {}ms",
103            path.to_string_lossy(),
104            time.elapsed().as_millis()
105        );
106        Ok(out)
107    }
108
109    pub fn parse<R: Read>(mut r: R) -> CalyxResult<ast::NamespaceDef> {
110        let mut buf = String::new();
111        r.read_to_string(&mut buf).map_err(|err| {
112            calyx_utils::Error::invalid_file(format!(
113                "Failed to parse buffer: {err}",
114            ))
115        })?;
116        // Save the input string to the position table
117        let file = GlobalPositionTable::add_file("<stdin>".to_string(), buf);
118        let user_data = UserData { file };
119        let content = GlobalPositionTable::get_source(file);
120
121        // Parse the input
122        let inputs =
123            CalyxParser::parse_with_userdata(Rule::file, content, user_data)
124                .map_err(|e| {
125                    calyx_utils::Error::parse_error(e.variant.message())
126                        .with_pos(&Self::error_span(&e, file))
127                })?;
128        let input = inputs.single().map_err(|e| {
129            calyx_utils::Error::parse_error(e.variant.message())
130                .with_pos(&Self::error_span(&e, file))
131        })?;
132        let out = CalyxParser::file(input).map_err(|e| {
133            calyx_utils::Error::parse_error(e.variant.message())
134                .with_pos(&Self::error_span(&e, file))
135        })?;
136        Ok(out)
137    }
138
139    fn get_span(node: &Node) -> GPosIdx {
140        let ud = node.user_data();
141        let sp = node.as_span();
142        let pos = GlobalPositionTable::add_pos(ud.file, sp.start(), sp.end());
143        GPosIdx(pos)
144    }
145
146    fn error_span(error: &pest::error::Error<Rule>, file: FileIdx) -> GPosIdx {
147        let (start, end) = match error.location {
148            pest::error::InputLocation::Pos(off) => (off, off + 1),
149            pest::error::InputLocation::Span((start, end)) => (start, end),
150        };
151        let pos = GlobalPositionTable::add_pos(file, start, end);
152        GPosIdx(pos)
153    }
154
155    #[allow(clippy::result_large_err)]
156    fn guard_expr_helper(
157        ud: UserData,
158        pairs: pest::iterators::Pairs<Rule>,
159    ) -> ParseResult<Box<GuardExpr>> {
160        PRATT
161            .map_primary(|primary| match primary.as_rule() {
162                Rule::term => {
163                    Self::term(Node::new_with_user_data(primary, ud.clone()))
164                        .map(Box::new)
165                }
166                x => unreachable!("Unexpected rule {:?} for guard_expr", x),
167            })
168            .map_infix(|lhs, op, rhs| {
169                Ok(match op.as_rule() {
170                    Rule::guard_or => Box::new(GuardExpr::Or(lhs?, rhs?)),
171                    Rule::guard_and => Box::new(GuardExpr::And(lhs?, rhs?)),
172                    _ => unreachable!(),
173                })
174            })
175            .parse(pairs)
176    }
177
178    #[allow(clippy::result_large_err)]
179    fn static_guard_expr_helper(
180        ud: UserData,
181        pairs: pest::iterators::Pairs<Rule>,
182    ) -> ParseResult<Box<StaticGuardExpr>> {
183        PRATT
184            .map_primary(|primary| match primary.as_rule() {
185                Rule::static_term => Self::static_term(
186                    Node::new_with_user_data(primary, ud.clone()),
187                )
188                .map(Box::new),
189                x => unreachable!(
190                    "Unexpected rule {:?} for static_guard_expr",
191                    x
192                ),
193            })
194            .map_infix(|lhs, op, rhs| {
195                Ok(match op.as_rule() {
196                    Rule::guard_or => Box::new(StaticGuardExpr::Or(lhs?, rhs?)),
197                    Rule::guard_and => {
198                        Box::new(StaticGuardExpr::And(lhs?, rhs?))
199                    }
200                    _ => unreachable!(),
201                })
202            })
203            .parse(pairs)
204    }
205
206    #[cfg(test)]
207    /// A test helper for parsing the new metadata table
208    pub fn parse_source_info_table(
209        input: &str,
210    ) -> Result<SourceInfoResult<SourceInfoTable>, Box<Error<Rule>>> {
211        let inputs = CalyxParser::parse_with_userdata(
212            Rule::source_info_table,
213            input,
214            UserData {
215                file: GlobalPositionTable::add_file("".into(), "".into()),
216            },
217        )?;
218        let input = inputs.single()?;
219        Ok(CalyxParser::source_info_table(input)?)
220    }
221}
222
223#[allow(clippy::large_enum_variant)]
224enum ExtOrComp {
225    Ext((Option<PosString>, Vec<Primitive>)),
226    Comp(ComponentDef),
227    PrimInline(Primitive),
228}
229
230#[pest_consume::parser]
231impl CalyxParser {
232    fn EOI(_input: Node) -> ParseResult<()> {
233        Ok(())
234    }
235
236    fn semi(_input: Node) -> ParseResult<()> {
237        Ok(())
238    }
239
240    fn comma_req(_input: Node) -> ParseResult<()> {
241        Ok(())
242    }
243    fn comma(input: Node) -> ParseResult<()> {
244        match_nodes!(
245            input.clone().into_children();
246            [comma_req(_)] => Ok(()),
247            [] => Err(input.error("expected comma"))
248        )
249    }
250
251    fn comb(_input: Node) -> ParseResult<()> {
252        Ok(())
253    }
254
255    fn static_word(_input: Node) -> ParseResult<()> {
256        Ok(())
257    }
258
259    fn reference(_input: Node) -> ParseResult<()> {
260        Ok(())
261    }
262
263    // ================ Literals =====================
264    fn identifier(input: Node) -> ParseResult<Id> {
265        Ok(Id::new(input.as_str()))
266    }
267
268    fn bitwidth(input: Node) -> ParseResult<u64> {
269        input
270            .as_str()
271            .parse::<u64>()
272            .map_err(|_| input.error("Expected valid bitwidth"))
273    }
274
275    fn static_annotation(input: Node) -> ParseResult<std::num::NonZeroU64> {
276        Ok(match_nodes!(
277            input.into_children();
278            [static_word(_), latency_annotation(latency)] => latency,
279        ))
280    }
281
282    fn static_optional_latency(
283        input: Node,
284    ) -> ParseResult<Option<std::num::NonZeroU64>> {
285        Ok(match_nodes!(
286            input.into_children();
287            [static_word(_), latency_annotation(latency)] => Some(latency),
288            [static_word(_)] => None,
289        ))
290    }
291
292    fn both_comb_static(
293        input: Node,
294    ) -> ParseResult<Option<std::num::NonZeroU64>> {
295        Err(input.error("Cannot have both comb and static annotations"))
296    }
297
298    fn comb_or_static(
299        input: Node,
300    ) -> ParseResult<Option<std::num::NonZeroU64>> {
301        match_nodes!(
302            input.clone().into_children();
303            [both_comb_static(_)] => unreachable!("both_comb_static did not error"),
304            [comb(_)] => Ok(None),
305            [static_annotation(latency)] => Ok(Some(latency)),
306        )
307    }
308
309    fn bad_num(input: Node) -> ParseResult<u64> {
310        Err(input.error("Expected number with bitwidth (like 32'd10)."))
311    }
312
313    fn hex(input: Node) -> ParseResult<u64> {
314        u64::from_str_radix(input.as_str(), 16)
315            .map_err(|_| input.error("Expected hexadecimal number"))
316    }
317    fn decimal(input: Node) -> ParseResult<u64> {
318        #[allow(clippy::from_str_radix_10)]
319        u64::from_str_radix(input.as_str(), 10)
320            .map_err(|_| input.error("Expected decimal number"))
321    }
322    fn octal(input: Node) -> ParseResult<u64> {
323        u64::from_str_radix(input.as_str(), 8)
324            .map_err(|_| input.error("Expected octal number"))
325    }
326    fn binary(input: Node) -> ParseResult<u64> {
327        u64::from_str_radix(input.as_str(), 2)
328            .map_err(|_| input.error("Expected binary number"))
329    }
330
331    // Floats are parsed as strings and converted within the float_const rule.
332    // This is so that we can check and see if the number can be represented
333    // exactly with the given bitwidth.
334    fn float(input: Node) -> ParseResult<String> {
335        Ok(input.as_str().to_string())
336    }
337
338    fn num_lit(input: Node) -> ParseResult<BitNum> {
339        let span = Self::get_span(&input);
340        let num = match_nodes!(
341            input.clone().into_children();
342            [bitwidth(width), decimal(val)] => BitNum {
343                    width,
344                    num_type: NumType::Decimal,
345                    val,
346                    span
347                },
348            [bitwidth(width), hex(val)] => BitNum {
349                    width,
350                    num_type: NumType::Hex,
351                    val,
352                    span
353                },
354            [bitwidth(width), octal(val)] => BitNum {
355                    width,
356                    num_type: NumType::Octal,
357                    val,
358                    span
359                },
360            [bitwidth(width), binary(val)] => BitNum {
361                    width,
362                    num_type: NumType::Binary,
363                    val,
364                    span
365                },
366
367        );
368
369        // the below cast is safe since the width must be less than 64 for
370        // the given literal to be unrepresentable
371        if num.width == 0
372            || (num.width < 64 && u64::pow(2, num.width as u32) <= num.val)
373        {
374            let lit_str = match num.num_type {
375                NumType::Binary => format!("{:b}", num.val),
376                NumType::Decimal => format!("{}", num.val),
377                NumType::Octal => format!("{:o}", num.val),
378                NumType::Hex => format!("{:x}", num.val),
379            };
380            let bit_plural = if num.width == 1 { "bit" } else { "bits" };
381            Err(input.error(format!(
382                "Cannot represent given literal '{}' in {} {}",
383                lit_str, num.width, bit_plural
384            )))
385        } else {
386            Ok(num)
387        }
388    }
389
390    fn char(input: Node) -> ParseResult<&str> {
391        Ok(input.as_str())
392    }
393
394    fn string_lit(input: Node) -> ParseResult<PosString> {
395        let span = Self::get_span(&input);
396        Ok(match_nodes!(
397            input.into_children();
398            [char(c)..] => PosString::new(c.collect::<Vec<_>>().join(""), span)
399        ))
400    }
401
402    // ================ Attributes =====================
403    fn attribute(input: Node) -> ParseResult<ParseAttributeWrapper> {
404        match_nodes!(
405            input.clone().into_children();
406            [string_lit(key), bitwidth(num)] => Attribute::from_str(key.as_ref()).map(|attr| (attr, num).into()).map_err(|e| input.error(format!("{e:?}"))),
407            [string_lit(key), attr_set(nums)] => {
408                let attr = SetAttribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{e:?}")))?;
409                Ok((attr, nums).into())
410            }
411        )
412    }
413    fn attributes(input: Node) -> ParseResult<Attributes> {
414        match_nodes!(
415            input.clone().into_children();
416            [attribute(kvs)..] => kvs.collect::<Vec<_>>().try_into().map_err(|e| input.error(format!("{e:?}")))
417        )
418    }
419    fn name_with_attribute(input: Node) -> ParseResult<(Id, Attributes)> {
420        Ok(match_nodes!(
421            input.into_children();
422            [identifier(name), attributes(attrs)] => (name, attrs),
423            [identifier(name)] => (name, Attributes::default()),
424        ))
425    }
426
427    fn block_char(input: Node) -> ParseResult<&str> {
428        Ok(input.as_str())
429    }
430
431    fn block_string(input: Node) -> ParseResult<String> {
432        Ok(match_nodes!(
433            input.into_children();
434            [block_char(c)..] => c.collect::<String>().trim().to_string()
435        ))
436    }
437
438    fn attr_val(input: Node) -> ParseResult<u64> {
439        Ok(match_nodes!(
440            input.into_children();
441            [bitwidth(num)] => num
442        ))
443    }
444
445    fn attr_set(input: Node) -> ParseResult<Vec<u32>> {
446        Ok(match_nodes!(
447            input.into_children();
448            [bitwidth(num)..] => num.into_iter().map(|n| {let n_32: u32 = n.try_into().expect("set values must fit in a u32"); n_32}).collect()
449        ))
450    }
451
452    fn latency_annotation(input: Node) -> ParseResult<std::num::NonZeroU64> {
453        let num = match_nodes!(
454            input.clone().into_children();
455            [bitwidth(value)] => value,
456        );
457        if num == 0 {
458            Err(input.error("latency annotation of 0"))
459        } else {
460            Ok(std::num::NonZeroU64::new(num).unwrap())
461        }
462    }
463
464    fn at_attribute(input: Node) -> ParseResult<ParseAttributeWrapper> {
465        match_nodes!(
466            input.clone().into_children();
467            [identifier(key), attr_val(num)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{e:?}"))).map(|attr| (attr, num).into()),
468            [identifier(key), attr_set(nums)] => {
469                let attr = SetAttribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{e:?}")))?;
470                Ok((attr, nums).into())
471            },
472            [identifier(key)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{e:?}"))).map(|attr| (attr, 1).into()),
473        )
474    }
475
476    fn at_attributes(input: Node) -> ParseResult<Attributes> {
477        match_nodes!(
478            input.clone().into_children();
479            [at_attribute(kvs)..] => kvs.collect::<Vec<_>>().try_into().map_err(|e| input.error(format!("{e:?}")))
480        )
481    }
482
483    // ================ Signature =====================
484    fn params(input: Node) -> ParseResult<Vec<Id>> {
485        Ok(match_nodes!(
486            input.into_children();
487            [identifier(id)..] => id.collect()
488        ))
489    }
490
491    fn args(input: Node) -> ParseResult<Vec<u64>> {
492        Ok(match_nodes!(
493            input.into_children();
494            [bitwidth(bw)..] => bw.collect(),
495            [] => vec![]
496        ))
497    }
498
499    fn io_port(input: Node) -> ParseResult<(Id, Width, Attributes)> {
500        Ok(match_nodes!(
501            input.into_children();
502            [at_attributes(attrs), identifier(id), bitwidth(value)] =>
503                (id, Width::Const { value }, attrs),
504            [at_attributes(attrs), identifier(id), identifier(value)] =>
505                (id, Width::Param { value }, attrs)
506        ))
507    }
508
509    fn inputs(input: Node) -> ParseResult<Vec<PortDef<Width>>> {
510        Ok(match_nodes!(
511            input.into_children();
512            [io_port((name, width, attributes))] => {
513                let pd = PortDef::new(
514                    name, width, Direction::Input, attributes
515                );
516                vec![pd]
517            },
518            [io_port((name, width, attributes)), comma(_), inputs(rest)] => {
519                let pd = PortDef::new(
520                    name, width, Direction::Input, attributes
521                );
522                let mut v = vec![pd];
523                v.extend(rest);
524                v
525            }
526        ))
527    }
528
529    fn outputs(input: Node) -> ParseResult<Vec<PortDef<Width>>> {
530        Ok(match_nodes!(
531            input.into_children();
532            [io_port((name, width, attributes))] => {
533                let pd = PortDef::new(
534                    name, width, Direction::Output, attributes
535                );
536                vec![pd]
537            },
538            [io_port((name, width, attributes)), comma(_), outputs(rest)] => {
539                let pd = PortDef::new(
540                    name, width, Direction::Output, attributes
541                );
542                let mut v = vec![pd];
543                v.extend(rest);
544                v
545            }
546        ))
547    }
548
549    fn signature(input: Node) -> ParseResult<Vec<PortDef<Width>>> {
550        Ok(match_nodes!(
551            input.into_children();
552            // NOTE(rachit): We expect the signature to be extended to have `go`,
553            // `done`, `reset,`, and `clk`.
554            [] => Vec::with_capacity(4),
555            [inputs(ins)] =>  ins ,
556            [outputs(outs)] =>  outs ,
557            [inputs(ins), outputs(outs)] => {
558                ins.into_iter().chain(outs.into_iter()).collect()
559            },
560        ))
561    }
562
563    // ==============Primitives=====================
564    fn sig_with_params(
565        input: Node,
566    ) -> ParseResult<(Vec<Id>, Vec<PortDef<Width>>)> {
567        Ok(match_nodes!(
568            input.into_children();
569            [params(p), signature(s)] => (p, s),
570            [signature(s)] => (vec![], s),
571        ))
572    }
573    fn primitive(input: Node) -> ParseResult<Primitive> {
574        let span = Self::get_span(&input);
575        Ok(match_nodes!(
576            input.into_children();
577            [name_with_attribute((name, attrs)), sig_with_params((p, s))] => Primitive {
578                name,
579                params: p,
580                signature: s,
581                attributes: attrs.add_span(span),
582                is_comb: false,
583                latency: None,
584                body: None,
585            },
586            [comb_or_static(cs_res), name_with_attribute((name, attrs)), sig_with_params((p, s))] => Primitive {
587                name,
588                params: p,
589                signature: s,
590                attributes: attrs.add_span(span),
591                is_comb: cs_res.is_none(),
592                latency: cs_res,
593                body: None,
594            }
595        ))
596    }
597
598    // ================ Cells =====================
599    fn float_const(input: Node) -> ParseResult<ast::Cell> {
600        let span = Self::get_span(&input);
601        Ok(match_nodes!(
602            input.clone().into_children();
603            [
604                at_attributes(attrs),
605                identifier(id),
606                bitwidth(rep),
607                bitwidth(width),
608                float(val)
609            ] => {
610                let v = match float::parse(rep, width, val) {
611                    Ok(v) => v,
612                    Err(e) => return Err(input.error(format!("{e:?}")))
613                };
614                ast::Cell::from(
615                    id,
616                    Id::from("std_float_const"),
617                    vec![rep, width, v],
618                    attrs.add_span(span),
619                    false
620                )
621            },
622            [
623                at_attributes(attrs),
624                reference(_),
625                identifier(id),
626                bitwidth(rep),
627                bitwidth(width),
628                float(val)
629            ] => {
630                let v = match float::parse(rep, width, val) {
631                    Ok(v) => v,
632                    Err(e) => return Err(input.error(format!("{e:?}")))
633                };
634                ast::Cell::from(
635                    id,
636                    Id::from("std_float_const"),
637                    vec![rep, width, v],
638                    attrs.add_span(span),
639                    true
640                )},
641        ))
642    }
643
644    fn cell_without_semi(input: Node) -> ParseResult<ast::Cell> {
645        let span = Self::get_span(&input);
646        Ok(match_nodes!(
647            input.into_children();
648            [float_const(fl)] => fl,
649            [at_attributes(attrs), reference(_), identifier(id), identifier(prim), args(args)] =>
650            ast::Cell::from(id, prim, args, attrs.add_span(span),true),
651            [at_attributes(attrs), identifier(id), identifier(prim), args(args)] =>
652            ast::Cell::from(id, prim, args, attrs.add_span(span),false)
653        ))
654    }
655
656    fn cell(input: Node) -> ParseResult<ast::Cell> {
657        match_nodes!(
658            input.clone().into_children();
659            [cell_without_semi(_)] =>
660                Err(input.error("Declaration is missing `;`")),
661            [cell_without_semi(node), semi(_)] => Ok(node),
662        )
663    }
664
665    fn cells(input: Node) -> ParseResult<Vec<ast::Cell>> {
666        Ok(match_nodes!(
667                input.into_children();
668                [cell(cells)..] => cells.collect()
669        ))
670    }
671
672    // ================ Wires =====================
673    fn port(input: Node) -> ParseResult<ast::Port> {
674        Ok(match_nodes!(
675            input.into_children();
676            [identifier(component), identifier(port)] =>
677                ast::Port::Comp { component, port },
678            [identifier(port)] => ast::Port::This { port }
679        ))
680    }
681
682    fn hole(input: Node) -> ParseResult<ast::Port> {
683        Ok(match_nodes!(
684            input.into_children();
685            [identifier(struct_elem), identifier(name)] => ast::Port::Hole { struct_elem, name }
686        ))
687    }
688
689    #[allow(clippy::upper_case_acronyms)]
690    fn LHS(input: Node) -> ParseResult<ast::Port> {
691        Ok(match_nodes!(
692            input.into_children();
693            [port(port)] => port,
694            [hole(hole)] => hole
695        ))
696    }
697
698    fn expr(input: Node) -> ParseResult<ast::Atom> {
699        match_nodes!(
700            input.into_children();
701            [LHS(port)] => Ok(ast::Atom::Port(port)),
702            [num_lit(num)] => Ok(ast::Atom::Num(num)),
703            [bad_num(_)] => unreachable!("bad_num returned non-error result"),
704        )
705    }
706
707    fn guard_eq(_input: Node) -> ParseResult<()> {
708        Ok(())
709    }
710    fn guard_neq(_input: Node) -> ParseResult<()> {
711        Ok(())
712    }
713    fn guard_leq(_input: Node) -> ParseResult<()> {
714        Ok(())
715    }
716    fn guard_geq(_input: Node) -> ParseResult<()> {
717        Ok(())
718    }
719    fn guard_lt(_input: Node) -> ParseResult<()> {
720        Ok(())
721    }
722    fn guard_gt(_input: Node) -> ParseResult<()> {
723        Ok(())
724    }
725
726    fn cmp_expr(input: Node) -> ParseResult<ast::CompGuard> {
727        Ok(match_nodes!(
728            input.into_children();
729            [expr(l), guard_eq(_), expr(r)] => (GC::Eq, l, r),
730            [expr(l), guard_neq(_), expr(r)] => (GC::Neq, l, r),
731            [expr(l), guard_geq(_), expr(r)] => (GC::Geq, l, r),
732            [expr(l), guard_leq(_), expr(r)] => (GC::Leq, l, r),
733            [expr(l), guard_gt(_), expr(r)] =>  (GC::Gt, l, r),
734            [expr(l), guard_lt(_), expr(r)] =>  (GC::Lt, l, r),
735        ))
736    }
737
738    fn guard_not(_input: Node) -> ParseResult<()> {
739        Ok(())
740    }
741
742    fn guard_expr(input: Node) -> ParseResult<Box<GuardExpr>> {
743        let ud = input.user_data().clone();
744        Self::guard_expr_helper(ud, input.into_pair().into_inner())
745    }
746
747    fn static_guard_expr(input: Node) -> ParseResult<Box<StaticGuardExpr>> {
748        let ud = input.user_data().clone();
749        Self::static_guard_expr_helper(ud, input.into_pair().into_inner())
750    }
751
752    fn term(input: Node) -> ParseResult<ast::GuardExpr> {
753        Ok(match_nodes!(
754            input.into_children();
755            [guard_expr(guard)] => *guard,
756            [cmp_expr((gc, a1, a2))] => ast::GuardExpr::CompOp((gc, a1, a2)),
757            [expr(e)] => ast::GuardExpr::Atom(e),
758            [guard_not(_), expr(e)] => {
759                ast::GuardExpr::Not(Box::new(ast::GuardExpr::Atom(e)))
760            },
761            [guard_not(_), cmp_expr((gc, a1, a2))] => {
762                ast::GuardExpr::Not(Box::new(ast::GuardExpr::CompOp((gc, a1, a2))))
763            },
764            [guard_not(_), guard_expr(e)] => {
765                ast::GuardExpr::Not(e)
766            },
767            [guard_not(_), expr(e)] =>
768                ast::GuardExpr::Not(Box::new(ast::GuardExpr::Atom(e)))
769        ))
770    }
771
772    fn static_term(input: Node) -> ParseResult<ast::StaticGuardExpr> {
773        Ok(match_nodes!(
774            input.into_children();
775            [static_timing_expr(interval)] => ast::StaticGuardExpr::StaticInfo(interval),
776            [static_guard_expr(guard)] => *guard,
777            [cmp_expr((gc, a1, a2))] => ast::StaticGuardExpr::CompOp((gc, a1, a2)),
778            [expr(e)] => ast::StaticGuardExpr::Atom(e),
779            [guard_not(_), expr(e)] => {
780                ast::StaticGuardExpr::Not(Box::new(ast::StaticGuardExpr::Atom(e)))
781            },
782            [guard_not(_), cmp_expr((gc, a1, a2))] => {
783                ast::StaticGuardExpr::Not(Box::new(ast::StaticGuardExpr::CompOp((gc, a1, a2))))
784            },
785            [guard_not(_), static_guard_expr(e)] => {
786                ast::StaticGuardExpr::Not(e)
787            },
788            [guard_not(_), expr(e)] =>
789                ast::StaticGuardExpr::Not(Box::new(ast::StaticGuardExpr::Atom(e)))
790        ))
791    }
792
793    fn switch_stmt(input: Node) -> ParseResult<ast::Guard> {
794        Ok(match_nodes!(
795            input.into_children();
796            [guard_expr(guard), expr(expr)] => ast::Guard { guard: Some(*guard), expr },
797        ))
798    }
799
800    fn static_switch_stmt(input: Node) -> ParseResult<ast::StaticGuard> {
801        Ok(match_nodes!(
802            input.into_children();
803            [static_guard_expr(guard), expr(expr)] => ast::StaticGuard { guard: Some(*guard), expr },
804        ))
805    }
806
807    fn wire(input: Node) -> ParseResult<ast::Wire> {
808        let span = Self::get_span(&input);
809        Ok(match_nodes!(
810            input.into_children();
811            [at_attributes(attrs), LHS(dest), expr(expr)] => ast::Wire {
812                src: ast::Guard { guard: None, expr },
813                dest,
814                attributes: attrs.add_span(span),
815            },
816            [at_attributes(attrs), LHS(dest), switch_stmt(src)] => ast::Wire {
817                src,
818                dest,
819                attributes: attrs.add_span(span),
820            }
821        ))
822    }
823
824    fn static_wire(input: Node) -> ParseResult<ast::StaticWire> {
825        let span = Self::get_span(&input);
826        Ok(match_nodes!(
827            input.into_children();
828            [at_attributes(attrs), LHS(dest), expr(expr)] => ast::StaticWire {
829                src: ast::StaticGuard { guard: None, expr },
830                dest,
831                attributes: attrs.add_span(span),
832            },
833            [at_attributes(attrs), LHS(dest), static_switch_stmt(src)] => ast::StaticWire {
834                src,
835                dest,
836                attributes: attrs.add_span(span),
837            }
838        ))
839    }
840
841    fn static_timing_expr(input: Node) -> ParseResult<(u64, u64)> {
842        Ok(match_nodes!(
843            input.into_children();
844            [bitwidth(single_num)] => (single_num, single_num+1),
845            [bitwidth(start_interval), bitwidth(end_interval)] => (start_interval, end_interval)
846        ))
847    }
848
849    fn group(input: Node) -> ParseResult<ast::Group> {
850        let span = Self::get_span(&input);
851        Ok(match_nodes!(
852            input.into_children();
853            [name_with_attribute((name, attrs)), wire(wire)..] => ast::Group {
854                name,
855                attributes: attrs.add_span(span),
856                wires: wire.collect(),
857                is_comb: false,
858            },
859            [comb(_), name_with_attribute((name, attrs)), wire(wire)..] => ast::Group {
860                name,
861                attributes: attrs.add_span(span),
862                wires: wire.collect(),
863                is_comb: true,
864            }
865        ))
866    }
867
868    fn static_group(input: Node) -> ParseResult<ast::StaticGroup> {
869        let span = Self::get_span(&input);
870        Ok(match_nodes!(
871            input.into_children();
872            [static_annotation(latency), name_with_attribute((name, attrs)), static_wire(wire)..] => ast::StaticGroup {
873                name,
874                attributes: attrs.add_span(span),
875                wires: wire.collect(),
876                latency,
877            }
878        ))
879    }
880
881    /// Parses in the state indices, which are unsigned integers in range `0..n`
882    fn state_idx(input: Node) -> ParseResult<u64> {
883        input
884            .as_str()
885            .parse::<u64>()
886            .map_err(|_| input.error("Expected valid state index"))
887    }
888
889    /// Parses the conditional transitions, which are of form `GuardExpr ->` state index,
890    /// or the default case, `default ->` state index. The conditional transitions
891    /// are evaluated sequentially, so the default case is treated like an `else` or
892    /// like the default case of a verilog case statement.
893    fn transition_rule(
894        input: Node,
895    ) -> ParseResult<(Option<ast::GuardExpr>, u64)> {
896        Ok(match_nodes!(
897            input.into_children();
898            [guard_expr(guard_expr), state_idx(state)] => { // guard branch
899                let guard = Some(*guard_expr);
900                (guard, state)
901            },
902            [state_idx(state)] => { // default branch
903                let guard = None; // default case has no guard, just true value 1'b1
904                (guard, state)
905            }
906        ))
907    }
908
909    /// Parses the transition block, which comes after the `=>` in the state.
910    /// Transitions are either `Unconditional` (will always transition to a future state
911    /// no matter the assignments) or `Conditional` (with boolean expressions denoted a
912    /// `guard_state_pair` and a default)
913    fn transition(input: Node) -> ParseResult<Transition> {
914        Ok(match_nodes!(
915            input.into_children();
916            [
917                state_idx(idx)
918            ] => {
919                ast::Transition::Unconditional(idx)
920            },
921            [
922                transition_rule(pairs)..,
923            ] => {
924                // collects the pairs in the order the parser reads them
925                ast::Transition::Conditional(pairs.collect())
926            }
927        ))
928    }
929
930    /// Parses a single state within the `fsm` block. A state is denoted with its
931    /// respective unsigned integer state index, which is is enumerated from `0..n`
932    /// States have assignments, which is a vector of `Wire`s, and transitions.
933    fn state(input: Node) -> ParseResult<(u64, Vec<ast::Wire>, Transition)> {
934        Ok(match_nodes!(
935            input.into_children();
936            [
937                state_idx(idx),
938                wire(wires)..,
939                transition(trans)
940            ] => {
941                let state_wires : Vec<ast::Wire> = wires.collect();
942                (idx, state_wires, trans) // we collect the state_idxs to use for sorting later
943            }
944        ))
945    }
946
947    /// Parses the `fsm` block to pull out the fsm block name, attributes, and list of rules.
948    /// A rule is the set of assignments and transitions each state within the `fsm` is assigned to.
949    fn fsm(input: Node) -> ParseResult<ast::Fsm> {
950        let span = Self::get_span(&input);
951        Ok(match_nodes!(
952            input.into_children();
953            [name_with_attribute((name, attrs)), state(states)..] => {
954                let mut state_data = Vec::new();
955
956                for (state_idx, assignments, transition) in states {
957                    let fsm_state = ast::FSMState {
958                        assignments,
959                        transition,
960                    };
961                    state_data.push((state_idx, fsm_state));
962                }
963                // make sure to sort the rules by index to access the vector by state index.
964                state_data.sort_by(|(idx1, _), (idx2, _)| idx1.cmp(idx2));
965                let fsm_states : Vec<ast::FSMState> = state_data.into_iter().map(|(_, r)| r).collect();
966
967                ast::Fsm {
968                name,
969                attributes: attrs.add_span(span),
970                fsm_states,
971                }
972            }
973        ))
974    }
975
976    /// Parses all the connections within the `wires` block of a Calyx program.
977    fn connections(input: Node) -> ParseResult<ParsedConnections> {
978        let mut wires = Vec::new();
979        let mut groups = Vec::new();
980        let mut static_groups = Vec::new();
981        let mut fsms = Vec::new();
982        for node in input.into_children() {
983            match node.as_rule() {
984                Rule::wire => wires.push(Self::wire(node)?),
985                Rule::group => groups.push(Self::group(node)?),
986                Rule::static_group => {
987                    static_groups.push(Self::static_group(node)?)
988                }
989                Rule::fsm => fsms.push(Self::fsm(node)?),
990                _ => unreachable!(),
991            }
992        }
993        Ok((wires, groups, static_groups, fsms))
994    }
995
996    // ================ Control program =====================
997    fn invoke_arg(input: Node) -> ParseResult<(Id, ast::Atom)> {
998        Ok(match_nodes!(
999            input.into_children();
1000            [identifier(name), port(p)] => (name, ast::Atom::Port(p)),
1001            [identifier(name), num_lit(bn)] => (name, ast::Atom::Num(bn))
1002
1003        ))
1004    }
1005
1006    fn invoke_args(input: Node) -> ParseResult<Vec<(Id, ast::Atom)>> {
1007        Ok(match_nodes!(
1008            input.into_children();
1009            [invoke_arg(args)..] => args.collect()
1010        ))
1011    }
1012
1013    fn invoke_ref_arg(input: Node) -> ParseResult<(Id, Id)> {
1014        Ok(match_nodes!(
1015            input.into_children();
1016            [identifier(outcell), identifier(incell)] => (outcell, incell)
1017        ))
1018    }
1019
1020    fn invoke_ref_args(input: Node) -> ParseResult<Vec<(Id, Id)>> {
1021        Ok(match_nodes!(
1022            input.into_children();
1023            [invoke_ref_arg(args)..] => args.collect(),
1024            [] => Vec::new()
1025        ))
1026    }
1027
1028    fn invoke(input: Node) -> ParseResult<ast::Control> {
1029        let span = Self::get_span(&input);
1030        Ok(match_nodes!(
1031            input.into_children();
1032            [at_attributes(attrs), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs)] =>
1033                ast::Control::Invoke {
1034                    comp,
1035                    inputs,
1036                    outputs,
1037                    attributes: attrs.add_span(span),
1038                    comb_group: None,
1039                    ref_cells: cells
1040                },
1041            [at_attributes(attrs), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs), identifier(group)] =>
1042                ast::Control::Invoke {
1043                    comp,
1044                    inputs,
1045                    outputs,
1046                    attributes: attrs.add_span(span),
1047                    comb_group: Some(group),
1048                    ref_cells: cells
1049                },
1050        ))
1051    }
1052
1053    fn static_invoke(input: Node) -> ParseResult<ast::Control> {
1054        let span = Self::get_span(&input);
1055        Ok(match_nodes!(
1056            input.into_children();
1057            [at_attributes(attrs), static_optional_latency(latency), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs)] =>
1058                ast::Control::StaticInvoke {
1059                    comp,
1060                    inputs,
1061                    outputs,
1062                    attributes: attrs.add_span(span),
1063                    ref_cells: cells,
1064                    latency,
1065                    comb_group: None,
1066                },
1067                [at_attributes(attrs), static_optional_latency(latency), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs), identifier(group)] =>
1068                ast::Control::StaticInvoke {
1069                    comp,
1070                    inputs,
1071                    outputs,
1072                    attributes: attrs.add_span(span),
1073                    ref_cells: cells,
1074                    latency,
1075                    comb_group: Some(group),
1076                },
1077        ))
1078    }
1079
1080    fn empty(input: Node) -> ParseResult<ast::Control> {
1081        let span = Self::get_span(&input);
1082        Ok(match_nodes!(
1083            input.into_children();
1084            [at_attributes(attrs)] => ast::Control::Empty {
1085                attributes: attrs.add_span(span)
1086            }
1087        ))
1088    }
1089
1090    fn enable(input: Node) -> ParseResult<ast::Control> {
1091        let span = Self::get_span(&input);
1092        Ok(match_nodes!(
1093            input.into_children();
1094            [at_attributes(attrs), identifier(name)] => ast::Control::Enable {
1095                comp: name,
1096                attributes: attrs.add_span(span)
1097            }
1098        ))
1099    }
1100
1101    fn seq(input: Node) -> ParseResult<ast::Control> {
1102        let span = Self::get_span(&input);
1103        Ok(match_nodes!(
1104            input.into_children();
1105            [at_attributes(attrs), stmt(stmt)..] => ast::Control::Seq {
1106                stmts: stmt.collect(),
1107                attributes: attrs.add_span(span),
1108            }
1109        ))
1110    }
1111
1112    fn static_seq(input: Node) -> ParseResult<ast::Control> {
1113        let span = Self::get_span(&input);
1114        Ok(match_nodes!(
1115            input.into_children();
1116            [at_attributes(attrs), static_optional_latency(latency) ,stmt(stmt)..] => ast::Control::StaticSeq {
1117                stmts: stmt.collect(),
1118                attributes: attrs.add_span(span),
1119                latency,
1120            }
1121        ))
1122    }
1123
1124    fn par(input: Node) -> ParseResult<ast::Control> {
1125        let span = Self::get_span(&input);
1126        Ok(match_nodes!(
1127            input.into_children();
1128            [at_attributes(attrs), stmt(stmt)..] => ast::Control::Par {
1129                stmts: stmt.collect(),
1130                attributes: attrs.add_span(span),
1131            }
1132        ))
1133    }
1134
1135    fn static_par(input: Node) -> ParseResult<ast::Control> {
1136        let span = Self::get_span(&input);
1137        Ok(match_nodes!(
1138            input.into_children();
1139            [at_attributes(attrs), static_optional_latency(latency) ,stmt(stmt)..] => ast::Control::StaticPar {
1140                stmts: stmt.collect(),
1141                attributes: attrs.add_span(span),
1142                latency,
1143            }
1144        ))
1145    }
1146
1147    fn port_with(input: Node) -> ParseResult<(ast::Port, Option<Id>)> {
1148        Ok(match_nodes!(
1149            input.into_children();
1150            [port(port), identifier(cond)] => (port, Some(cond)),
1151            [port(port)] => (port, None),
1152        ))
1153    }
1154
1155    fn if_stmt(input: Node) -> ParseResult<ast::Control> {
1156        let span = Self::get_span(&input);
1157        Ok(match_nodes!(
1158            input.into_children();
1159            [at_attributes(attrs), port_with((port, cond)), block(stmt)] => ast::Control::If {
1160                port,
1161                cond,
1162                tbranch: Box::new(stmt),
1163                fbranch: Box::new(ast::Control::Empty { attributes: Attributes::default() }),
1164                attributes: attrs.add_span(span),
1165            },
1166            [at_attributes(attrs), port_with((port, cond)), block(tbranch), block(fbranch)] =>
1167                ast::Control::If {
1168                    port,
1169                    cond,
1170                    tbranch: Box::new(tbranch),
1171                    fbranch: Box::new(fbranch),
1172                    attributes: attrs.add_span(span),
1173                },
1174            [at_attributes(attrs), port_with((port, cond)), block(tbranch), if_stmt(fbranch)] =>
1175                ast::Control::If {
1176                    port,
1177                    cond,
1178                    tbranch: Box::new(tbranch),
1179                    fbranch: Box::new(fbranch),
1180                    attributes: attrs.add_span(span),
1181                },
1182
1183        ))
1184    }
1185
1186    fn static_if_stmt(input: Node) -> ParseResult<ast::Control> {
1187        let span = Self::get_span(&input);
1188        Ok(match_nodes!(
1189            input.into_children();
1190            [at_attributes(attrs), static_optional_latency(latency), port(port), block(stmt)] => ast::Control::StaticIf {
1191                port,
1192                tbranch: Box::new(stmt),
1193                fbranch: Box::new(ast::Control::Empty { attributes: Attributes::default() }),
1194                attributes: attrs.add_span(span),
1195                latency,
1196            },
1197            [at_attributes(attrs), static_optional_latency(latency), port(port), block(tbranch), block(fbranch)] =>
1198                ast::Control::StaticIf {
1199                    port,
1200                    tbranch: Box::new(tbranch),
1201                    fbranch: Box::new(fbranch),
1202                    attributes: attrs.add_span(span),
1203                    latency,
1204                },
1205            [at_attributes(attrs), static_optional_latency(latency), port(port), block(tbranch), static_if_stmt(fbranch)] =>
1206                ast::Control::StaticIf {
1207                    port,
1208                    tbranch: Box::new(tbranch),
1209                    fbranch: Box::new(fbranch),
1210                    attributes: attrs.add_span(span),
1211                    latency,
1212                }
1213        ))
1214    }
1215
1216    fn while_stmt(input: Node) -> ParseResult<ast::Control> {
1217        let span = Self::get_span(&input);
1218        Ok(match_nodes!(
1219            input.into_children();
1220            [at_attributes(attrs), port_with((port, cond)), block(stmt)] => ast::Control::While {
1221                port,
1222                cond,
1223                body: Box::new(stmt),
1224                attributes: attrs.add_span(span),
1225            }
1226        ))
1227    }
1228
1229    fn repeat_stmt(input: Node) -> ParseResult<ast::Control> {
1230        let span = Self::get_span(&input);
1231        Ok(match_nodes!(
1232            input.into_children();
1233            [at_attributes(attrs), bitwidth(num_repeats) , block(stmt)] => ast::Control::Repeat {
1234                num_repeats,
1235                body: Box::new(stmt),
1236                attributes: attrs.add_span(span),
1237            },
1238            [at_attributes(attrs), static_word(_), bitwidth(num_repeats) , block(stmt)] => ast::Control::StaticRepeat {
1239                num_repeats,
1240                body: Box::new(stmt),
1241                attributes: attrs.add_span(span),
1242            }
1243        ))
1244    }
1245
1246    fn stmt(input: Node) -> ParseResult<ast::Control> {
1247        Ok(match_nodes!(
1248            input.into_children();
1249            [enable(data)] => data,
1250            [empty(data)] => data,
1251            [invoke(data)] => data,
1252            [static_invoke(data)] => data,
1253            [seq(data)] => data,
1254            [static_seq(data)] => data,
1255            [par(data)] => data,
1256            [static_par(data)] => data,
1257            [if_stmt(data)] => data,
1258            [static_if_stmt(data)] => data,
1259            [while_stmt(data)] => data,
1260            [repeat_stmt(data)] => data,
1261        ))
1262    }
1263
1264    fn block(input: Node) -> ParseResult<ast::Control> {
1265        Ok(match_nodes!(
1266            input.into_children();
1267            [stmt(stmt)] => stmt,
1268            [stmts_without_block(seq)] => seq,
1269        ))
1270    }
1271
1272    fn stmts_without_block(input: Node) -> ParseResult<ast::Control> {
1273        match_nodes!(
1274            input.clone().into_children();
1275            [stmt(stmt)..] => Ok(ast::Control::Seq {
1276                stmts: stmt.collect(),
1277                attributes: Attributes::default(),
1278            })
1279        )
1280    }
1281
1282    fn control(input: Node) -> ParseResult<ast::Control> {
1283        Ok(match_nodes!(
1284            input.into_children();
1285            [block(stmt)] => stmt,
1286            [] => ast::Control::empty()
1287        ))
1288    }
1289
1290    fn component(input: Node) -> ParseResult<ComponentDef> {
1291        let span = Self::get_span(&input);
1292        match_nodes!(
1293            input.clone().into_children();
1294            [
1295                comb_or_static(cs_res),
1296                name_with_attribute((name, attributes)),
1297                signature(sig),
1298                cells(cells),
1299                connections(connections)
1300            ] => {
1301                if cs_res.is_some() {
1302                    Err(input.error("Static Component must have defined control"))?;
1303                }
1304                let (continuous_assignments, groups, static_groups, fsms) = connections;
1305                let sig = sig.into_iter().map(|pd| {
1306                    if let Width::Const { value } = pd.width {
1307                        Ok(PortDef::new(
1308                            pd.name(),
1309                            value,
1310                            pd.direction,
1311                            pd.attributes
1312                        ))
1313                    } else {
1314                        Err(input.error("Components cannot use parameters"))
1315                    }
1316                }).collect::<Result<_, _>>()?;
1317                Ok(ComponentDef {
1318                    name,
1319                    signature: sig,
1320                    cells,
1321                    groups,
1322                    static_groups,
1323                    fsms,
1324                    continuous_assignments,
1325                    control: Control::empty(),
1326                    attributes: attributes.add_span(span),
1327                    is_comb: true,
1328                    latency: None,
1329                })
1330            },
1331            [
1332                name_with_attribute((name, attributes)),
1333                signature(sig),
1334                cells(cells),
1335                connections(connections),
1336                control(control)
1337            ] => {
1338                let (continuous_assignments, groups, static_groups, fsms) = connections;
1339                let sig = sig.into_iter().map(|pd| {
1340                    if let Width::Const { value } = pd.width {
1341                        Ok(PortDef::new(
1342                            pd.name(),
1343                            value,
1344                            pd.direction,
1345                            pd.attributes
1346                        ))
1347                    } else {
1348                        Err(input.error("Components cannot use parameters"))
1349                    }
1350                }).collect::<Result<_, _>>()?;
1351                Ok(ComponentDef {
1352                    name,
1353                    signature: sig,
1354                    cells,
1355                    groups,
1356                    static_groups,
1357                    fsms,
1358                    continuous_assignments,
1359                    control,
1360                    attributes: attributes.add_span(span),
1361                    is_comb: false,
1362                    latency: None,
1363                })
1364            },
1365            [
1366                comb_or_static(cs_res),
1367                name_with_attribute((name, attributes)),
1368                signature(sig),
1369                cells(cells),
1370                connections(connections),
1371                control(control),
1372            ] => {
1373                let (continuous_assignments, groups, static_groups, fsms) = connections;
1374                let sig = sig.into_iter().map(|pd| {
1375                    if let Width::Const { value } = pd.width {
1376                        Ok(PortDef::new(
1377                            pd.name(),
1378                            value,
1379                            pd.direction,
1380                            pd.attributes
1381                        ))
1382                    } else {
1383                        Err(input.error("Components cannot use parameters"))
1384                    }
1385                }).collect::<Result<_, _>>()?;
1386                Ok(ComponentDef {
1387                    name,
1388                    signature: sig,
1389                    cells,
1390                    groups,
1391                    static_groups,
1392                    fsms,
1393                    continuous_assignments,
1394                    control,
1395                    attributes: attributes.add_span(span),
1396                    is_comb: cs_res.is_none(),
1397                    latency: cs_res,
1398                })
1399            },
1400        )
1401    }
1402
1403    fn imports(input: Node) -> ParseResult<Vec<PosString>> {
1404        Ok(match_nodes!(
1405            input.into_children();
1406            [string_lit(path)..] => path.collect()
1407        ))
1408    }
1409
1410    fn ext(input: Node) -> ParseResult<(Option<PosString>, Vec<Primitive>)> {
1411        Ok(match_nodes!(
1412            input.into_children();
1413            [string_lit(file), primitive(prims)..] => (Some(file), prims.collect())
1414        ))
1415    }
1416
1417    fn prim_inline(input: Node) -> ParseResult<Primitive> {
1418        let span = Self::get_span(&input);
1419        Ok(match_nodes!(
1420            input.into_children();
1421            [name_with_attribute((name, attrs)), sig_with_params((p, s)), block_string(b)] => {
1422            Primitive {
1423                name,
1424                params: p,
1425                signature: s,
1426                attributes: attrs.add_span(span),
1427                is_comb: false,
1428                latency: None,
1429                body: Some(b),
1430            }},
1431            [comb_or_static(cs_res), name_with_attribute((name, attrs)), sig_with_params((p, s)), block_string(b)] => Primitive {
1432                name,
1433                params: p,
1434                signature: s,
1435                attributes: attrs.add_span(span),
1436                is_comb: cs_res.is_none(),
1437                latency: cs_res,
1438                body: Some(b),
1439            }
1440        ))
1441    }
1442
1443    fn extern_or_component(input: Node) -> ParseResult<ExtOrComp> {
1444        Ok(match_nodes!(
1445            input.into_children();
1446            [component(comp)] => ExtOrComp::Comp(comp),
1447            [ext(ext)] => ExtOrComp::Ext(ext),
1448            [prim_inline(prim_inline)] => ExtOrComp::PrimInline(prim_inline),
1449        ))
1450    }
1451
1452    fn externs_and_comps(
1453        input: Node,
1454    ) -> ParseResult<impl Iterator<Item = ExtOrComp>> {
1455        Ok(match_nodes!(input.into_children();
1456            [extern_or_component(e)..] => e
1457        ))
1458    }
1459
1460    fn any_char(input: Node) -> ParseResult<String> {
1461        Ok(input.as_str().into())
1462    }
1463
1464    fn metadata_char(input: Node) -> ParseResult<String> {
1465        Ok(match_nodes!(input.into_children();
1466            [any_char(c)] => c,
1467        ))
1468    }
1469
1470    fn metadata(input: Node) -> ParseResult<String> {
1471        Ok(match_nodes!(input.into_children();
1472            [metadata_char(c)..] => c.collect::<String>().trim().into()
1473        ))
1474    }
1475
1476    // Source Info Table
1477
1478    fn path_text(input: Node) -> ParseResult<PathBuf> {
1479        Ok(PathBuf::from(input.as_str().trim()))
1480    }
1481
1482    fn file_entry(input: Node) -> ParseResult<(MetadataFileId, PathBuf)> {
1483        Ok(match_nodes!(input.into_children();
1484            [bitwidth(n), path_text(p)] => (MetadataFileId::new(n.try_into().expect("file ids must fit in a u32")), p)
1485        ))
1486    }
1487
1488    fn file_header(_input: Node) -> ParseResult<()> {
1489        Ok(())
1490    }
1491
1492    fn file_table(
1493        input: Node,
1494    ) -> ParseResult<impl IntoIterator<Item = (MetadataFileId, PathBuf)>> {
1495        Ok(match_nodes!(input.into_children();
1496            [file_header(_), file_entry(e)..] => e))
1497    }
1498
1499    fn position_header(_input: Node) -> ParseResult<()> {
1500        Ok(())
1501    }
1502
1503    fn position_entry(
1504        input: Node,
1505    ) -> ParseResult<(PositionId, MetadataFileId, LineNum)> {
1506        Ok(match_nodes!(input.into_children();
1507            [bitwidth(pos_num), bitwidth(file_num), bitwidth(line_no)] => {
1508                let pos_num = pos_num.try_into().expect("position ids must fit in a u32");
1509                let file_num = file_num.try_into().expect("file ids must fit in a u32");
1510                let line_no = line_no.try_into().expect("line numbers must fit in a u32");
1511                (PositionId::new(pos_num), MetadataFileId::new(file_num), LineNum::new(line_no))}
1512        ))
1513    }
1514
1515    fn position_table(
1516        input: Node,
1517    ) -> ParseResult<
1518        impl IntoIterator<Item = (PositionId, MetadataFileId, LineNum)>,
1519    > {
1520        Ok(match_nodes!(input.into_children();
1521                [position_header(_), position_entry(e)..] => e))
1522    }
1523
1524    fn source_info_table(
1525        input: Node,
1526    ) -> ParseResult<SourceInfoResult<SourceInfoTable>> {
1527        Ok(match_nodes!(input.into_children();
1528            [file_table(f), position_table(p)] => SourceInfoTable::new(f, p)
1529        ))
1530    }
1531
1532    // end new metadata
1533
1534    fn extra_info(
1535        input: Node,
1536    ) -> ParseResult<(Option<String>, Option<SourceInfoTable>)> {
1537        Ok(match_nodes!(input.into_children();
1538                [metadata(m)] => (Some(m), None),
1539                [source_info_table(s)] => {
1540                    if let Ok(s) = s {
1541                        (None, Some(s))
1542                    } else {
1543                        log::error!("{}", s.unwrap_err());
1544                        (None, None)
1545                    }
1546                },
1547                [metadata(m), source_info_table(s)] => {
1548                    if let Ok(s) = s {
1549                        (Some(m), Some(s))
1550                    } else {
1551                        log::error!("{}", s.unwrap_err());
1552                        (Some(m), None)
1553                    }
1554                },
1555                [source_info_table(s), metadata(m)] => {
1556                    if let Ok(s) = s {
1557                        (Some(m), Some(s))
1558                    } else {
1559                        log::error!("{}", s.unwrap_err());
1560                        (Some(m), None)
1561                    }
1562                }
1563        ))
1564    }
1565
1566    fn file(input: Node) -> ParseResult<ast::NamespaceDef> {
1567        Ok(match_nodes!(
1568            input.into_children();
1569            // There really seems to be no straightforward way to resolve this
1570            // duplication
1571            [imports(imports), externs_and_comps(mixed), extra_info(info), EOI(_)] => {
1572                let (mut metadata, source_info_table) = info;
1573                // remove empty metadata strings
1574                if let Some(m) = &metadata {
1575                    if m.is_empty() {
1576                        metadata = None;
1577                    }
1578                }
1579
1580                let mut namespace =
1581                    ast::NamespaceDef {
1582                        imports,
1583                        components: Vec::new(),
1584                        externs: Vec::new(),
1585                        metadata,
1586                         source_info_table
1587                    };
1588                for m in mixed {
1589                    match m {
1590                        ExtOrComp::Ext(ext) => namespace.externs.push(ext),
1591                        ExtOrComp::Comp(comp) => namespace.components.push(comp),
1592                        ExtOrComp::PrimInline(prim) => {
1593                            if let Some((_, prim_inlines)) = namespace.externs.iter_mut().find(|(filename, _)| filename.is_none()) {
1594                                prim_inlines.push(prim)
1595                            }
1596                            else{
1597                                namespace.externs.push((None, vec![prim]));
1598                            }
1599                        },
1600                    }
1601                }
1602                namespace
1603            },
1604            [imports(imports), externs_and_comps(mixed), EOI(_)] => {
1605                let mut namespace =
1606                    ast::NamespaceDef {
1607                        imports,
1608                        components: Vec::new(),
1609                        externs: Vec::new(),
1610                        metadata: None,
1611                        source_info_table: None
1612                    };
1613                for m in mixed {
1614                    match m {
1615                        ExtOrComp::Ext(ext) => namespace.externs.push(ext),
1616                        ExtOrComp::Comp(comp) => namespace.components.push(comp),
1617                        ExtOrComp::PrimInline(prim) => {
1618                            if let Some((_, prim_inlines)) = namespace.externs.iter_mut().find(|(filename, _)| filename.is_none()) {
1619                                prim_inlines.push(prim)
1620                            }
1621                            else{
1622                                namespace.externs.push((None, vec![prim]));
1623                            }
1624                        },
1625                    }
1626                }
1627                namespace
1628            },
1629
1630        ))
1631    }
1632}