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