Skip to main content

chipi_core/bindings/
parser.rs

1//! Lexer and recursive-descent parser for `*.bindings.chipi` files.
2//!
3//! The grammar is brace-based:
4//!
5//! ```text
6//! file       = (include | target)*
7//! include    = 'include' STRING
8//! target     = 'target' IDENT '{' target_body '}'
9//! ```
10//!
11//! Tokens:
12//! - `Ident`. Matches `[A-Za-z_][A-Za-z0-9_:]*`. `::` is part of paths.
13//! - `String`. Double-quoted.
14//! - `Number`. Decimal or `0x...` hex.
15//! - `{` `}` `<` `>` `=` `,`
16//! - `#`-to-EOL comments
17
18use std::collections::BTreeMap;
19use std::collections::HashSet;
20use std::path::{Path, PathBuf};
21
22use crate::config::Dispatch;
23use crate::error::{Error, ErrorKind, Span};
24
25use super::types::*;
26
27// ---------------------------------------------------------------------------
28// Lexer
29// ---------------------------------------------------------------------------
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32enum Tok {
33    Ident(String),
34    Str(String),
35    Num(u64),
36    LBrace,
37    RBrace,
38    LAngle,
39    RAngle,
40    Eq,
41    Comma,
42    Eof,
43}
44
45#[derive(Debug, Clone)]
46struct Token {
47    tok: Tok,
48    span: Span,
49}
50
51struct Lexer<'a> {
52    src: &'a [u8],
53    pos: usize,
54    line: usize,
55    col: usize,
56    file: String,
57}
58
59impl<'a> Lexer<'a> {
60    fn new(source: &'a str, filename: &str) -> Self {
61        Self {
62            src: source.as_bytes(),
63            pos: 0,
64            line: 1,
65            col: 1,
66            file: filename.to_string(),
67        }
68    }
69
70    fn span(&self, start_line: usize, start_col: usize, len: usize) -> Span {
71        Span::new(&self.file, start_line, start_col, len)
72    }
73
74    fn peek_byte(&self) -> Option<u8> {
75        self.src.get(self.pos).copied()
76    }
77
78    fn bump(&mut self) -> Option<u8> {
79        let b = self.peek_byte()?;
80        self.pos += 1;
81        if b == b'\n' {
82            self.line += 1;
83            self.col = 1;
84        } else {
85            self.col += 1;
86        }
87        Some(b)
88    }
89
90    fn skip_whitespace_and_comments(&mut self) {
91        loop {
92            match self.peek_byte() {
93                Some(b' ' | b'\t' | b'\n' | b'\r') => {
94                    self.bump();
95                }
96                Some(b'#') => {
97                    while let Some(b) = self.peek_byte() {
98                        if b == b'\n' {
99                            break;
100                        }
101                        self.bump();
102                    }
103                }
104                _ => break,
105            }
106        }
107    }
108
109    fn next_token(&mut self) -> Result<Token, Error> {
110        self.skip_whitespace_and_comments();
111        let start_line = self.line;
112        let start_col = self.col;
113        let start_pos = self.pos;
114
115        let b = match self.peek_byte() {
116            Some(b) => b,
117            None => {
118                return Ok(Token {
119                    tok: Tok::Eof,
120                    span: self.span(start_line, start_col, 0),
121                });
122            }
123        };
124
125        match b {
126            b'{' => {
127                self.bump();
128                Ok(Token {
129                    tok: Tok::LBrace,
130                    span: self.span(start_line, start_col, 1),
131                })
132            }
133            b'}' => {
134                self.bump();
135                Ok(Token {
136                    tok: Tok::RBrace,
137                    span: self.span(start_line, start_col, 1),
138                })
139            }
140            b'<' => {
141                self.bump();
142                Ok(Token {
143                    tok: Tok::LAngle,
144                    span: self.span(start_line, start_col, 1),
145                })
146            }
147            b'>' => {
148                self.bump();
149                Ok(Token {
150                    tok: Tok::RAngle,
151                    span: self.span(start_line, start_col, 1),
152                })
153            }
154            b'=' => {
155                self.bump();
156                Ok(Token {
157                    tok: Tok::Eq,
158                    span: self.span(start_line, start_col, 1),
159                })
160            }
161            b',' => {
162                self.bump();
163                Ok(Token {
164                    tok: Tok::Comma,
165                    span: self.span(start_line, start_col, 1),
166                })
167            }
168            b'"' => {
169                self.bump();
170                let mut s = String::new();
171                loop {
172                    match self.peek_byte() {
173                        None => {
174                            return Err(Error::new(
175                                ErrorKind::BindingsParse("unterminated string literal".to_string()),
176                                self.span(start_line, start_col, 1),
177                            ));
178                        }
179                        Some(b'"') => {
180                            self.bump();
181                            break;
182                        }
183                        Some(b'\\') => {
184                            self.bump();
185                            match self.bump() {
186                                Some(b'"') => s.push('"'),
187                                Some(b'\\') => s.push('\\'),
188                                Some(b'n') => s.push('\n'),
189                                Some(b't') => s.push('\t'),
190                                Some(c) => s.push(c as char),
191                                None => {
192                                    return Err(Error::new(
193                                        ErrorKind::BindingsParse(
194                                            "unterminated string escape".to_string(),
195                                        ),
196                                        self.span(start_line, start_col, 1),
197                                    ));
198                                }
199                            }
200                        }
201                        Some(c) => {
202                            s.push(c as char);
203                            self.bump();
204                        }
205                    }
206                }
207                let len = self.pos - start_pos;
208                Ok(Token {
209                    tok: Tok::Str(s),
210                    span: self.span(start_line, start_col, len),
211                })
212            }
213            b'0'..=b'9' => {
214                let mut s = String::new();
215                while let Some(c) = self.peek_byte() {
216                    if c.is_ascii_alphanumeric() || c == b'x' || c == b'X' {
217                        s.push(c as char);
218                        self.bump();
219                    } else {
220                        break;
221                    }
222                }
223                let n = if let Some(rest) = s.strip_prefix("0x").or(s.strip_prefix("0X")) {
224                    u64::from_str_radix(rest, 16)
225                } else {
226                    s.parse::<u64>()
227                };
228                let n = n.map_err(|_| {
229                    Error::new(
230                        ErrorKind::BindingsParse(format!("invalid number literal '{}'", s)),
231                        self.span(start_line, start_col, s.len()),
232                    )
233                })?;
234                let len = self.pos - start_pos;
235                Ok(Token {
236                    tok: Tok::Num(n),
237                    span: self.span(start_line, start_col, len),
238                })
239            }
240            c if is_ident_start(c) => {
241                let mut s = String::new();
242                while let Some(c) = self.peek_byte() {
243                    if is_ident_cont(c) {
244                        s.push(c as char);
245                        self.bump();
246                    } else if c == b':' && self.src.get(self.pos + 1) == Some(&b':') {
247                        s.push_str("::");
248                        self.bump();
249                        self.bump();
250                    } else if c == b'$' {
251                        // allow $VAR / ${VAR} inside path-like idents (for output paths
252                        // we use strings, so this is not strictly needed; kept for
253                        // robustness)
254                        s.push(c as char);
255                        self.bump();
256                    } else {
257                        break;
258                    }
259                }
260                let len = self.pos - start_pos;
261                Ok(Token {
262                    tok: Tok::Ident(s),
263                    span: self.span(start_line, start_col, len),
264                })
265            }
266            _ => Err(Error::new(
267                ErrorKind::BindingsParse(format!("unexpected character '{}'", b as char)),
268                self.span(start_line, start_col, 1),
269            )),
270        }
271    }
272}
273
274fn is_ident_start(c: u8) -> bool {
275    c.is_ascii_alphabetic() || c == b'_'
276}
277
278fn is_ident_cont(c: u8) -> bool {
279    c.is_ascii_alphanumeric() || c == b'_'
280}
281
282// ---------------------------------------------------------------------------
283// Parser
284// ---------------------------------------------------------------------------
285
286struct Parser<'a> {
287    lex: Lexer<'a>,
288    peeked: Option<Token>,
289    file_path: PathBuf,
290}
291
292/// Parse a bindings file (without resolving includes).
293pub fn parse(source: &str, file_path: &Path) -> Result<BindingsFile, Vec<Error>> {
294    let filename = file_path
295        .file_name()
296        .and_then(|s| s.to_str())
297        .unwrap_or("<bindings>");
298    let mut p = Parser {
299        lex: Lexer::new(source, filename),
300        peeked: None,
301        file_path: file_path.to_path_buf(),
302    };
303    p.parse_file()
304}
305
306/// Parse a bindings file from disk (without resolving includes).
307pub fn parse_file(path: &Path) -> Result<BindingsFile, Vec<Error>> {
308    let source = std::fs::read_to_string(path).map_err(|_| {
309        vec![Error::new(
310            ErrorKind::IncludeNotFound(path.display().to_string()),
311            Span::new(&path.display().to_string(), 1, 1, 0),
312        )]
313    })?;
314    parse(&source, path)
315}
316
317/// Parse a bindings file and recursively follow `include "*.bindings.chipi"`
318/// directives. Spec includes (`*.chipi`) are recorded but not parsed.
319pub fn parse_file_with_includes(path: &Path) -> Result<BindingsFile, Vec<Error>> {
320    let mut visited: HashSet<PathBuf> = HashSet::new();
321    parse_file_recursive(path, &mut visited)
322}
323
324fn parse_file_recursive(
325    path: &Path,
326    visited: &mut HashSet<PathBuf>,
327) -> Result<BindingsFile, Vec<Error>> {
328    let canonical = path.canonicalize().map_err(|_| {
329        vec![Error::new(
330            ErrorKind::IncludeNotFound(path.display().to_string()),
331            Span::new(&path.display().to_string(), 1, 1, 0),
332        )]
333    })?;
334    if !visited.insert(canonical.clone()) {
335        return Err(vec![Error::new(
336            ErrorKind::BindingsCircularInclude(path.display().to_string()),
337            Span::new(&path.display().to_string(), 1, 1, 0),
338        )]);
339    }
340    let mut file = parse_file(&canonical)?;
341    file.path = canonical.clone();
342    let base = canonical.parent().unwrap_or(Path::new(".")).to_path_buf();
343    let mut merged_targets: Vec<TargetBinding> = std::mem::take(&mut file.targets);
344    let mut merged_specs: Vec<(PathBuf, Span)> = std::mem::take(&mut file.spec_includes);
345
346    let bindings_inc = std::mem::take(&mut file.bindings_includes);
347    let mut resolved_bindings_inc: Vec<(PathBuf, Span)> = Vec::new();
348    for (rel, span) in bindings_inc {
349        let abs = if rel.is_absolute() {
350            rel
351        } else {
352            base.join(rel)
353        };
354        let inc = parse_file_recursive(&abs, visited)?;
355        // Deep-merge: pull in all transitively included bindings + specs.
356        merged_targets.extend(inc.targets);
357        merged_specs.extend(inc.spec_includes);
358        resolved_bindings_inc.push((inc.path, span));
359    }
360
361    // Resolve relative spec paths to canonical absolute paths.
362    let mut resolved_specs: Vec<(PathBuf, Span)> = Vec::new();
363    for (rel, span) in merged_specs {
364        let abs = if rel.is_absolute() {
365            rel
366        } else {
367            base.join(rel)
368        };
369        let canon = abs.canonicalize().unwrap_or(abs);
370        resolved_specs.push((canon, span));
371    }
372
373    file.targets = merged_targets;
374    file.spec_includes = resolved_specs;
375    file.bindings_includes = resolved_bindings_inc;
376    Ok(file)
377}
378
379impl<'a> Parser<'a> {
380    fn peek(&mut self) -> Result<&Token, Error> {
381        if self.peeked.is_none() {
382            self.peeked = Some(self.lex.next_token()?);
383        }
384        Ok(self.peeked.as_ref().unwrap())
385    }
386
387    /// Convenience: peek and return an owned copy so callers don't trip the
388    /// borrow checker when they need to call `self.next()` in the same
389    /// match arm.
390    fn peek_clone(&mut self) -> Result<Token, Error> {
391        Ok(self.peek()?.clone())
392    }
393
394    fn next(&mut self) -> Result<Token, Error> {
395        if let Some(t) = self.peeked.take() {
396            return Ok(t);
397        }
398        self.lex.next_token()
399    }
400
401    fn expect_ident(&mut self) -> Result<(String, Span), Error> {
402        let t = self.next()?;
403        match t.tok {
404            Tok::Ident(s) => Ok((s, t.span)),
405            other => Err(Error::new(
406                ErrorKind::BindingsParse(format!("expected identifier, got {:?}", other)),
407                t.span,
408            )),
409        }
410    }
411
412    fn expect_string(&mut self) -> Result<(String, Span), Error> {
413        let t = self.next()?;
414        match t.tok {
415            Tok::Str(s) => Ok((s, t.span)),
416            other => Err(Error::new(
417                ErrorKind::BindingsParse(format!("expected string literal, got {:?}", other)),
418                t.span,
419            )),
420        }
421    }
422
423    fn expect_number(&mut self) -> Result<(u64, Span), Error> {
424        let t = self.next()?;
425        match t.tok {
426            Tok::Num(n) => Ok((n, t.span)),
427            other => Err(Error::new(
428                ErrorKind::BindingsParse(format!("expected number, got {:?}", other)),
429                t.span,
430            )),
431        }
432    }
433
434    fn expect_lbrace(&mut self) -> Result<Span, Error> {
435        let t = self.next()?;
436        match t.tok {
437            Tok::LBrace => Ok(t.span),
438            other => Err(Error::new(
439                ErrorKind::BindingsParse(format!("expected '{{', got {:?}", other)),
440                t.span,
441            )),
442        }
443    }
444
445    fn parse_file(&mut self) -> Result<BindingsFile, Vec<Error>> {
446        let mut errors: Vec<Error> = Vec::new();
447        let mut spec_includes: Vec<(PathBuf, Span)> = Vec::new();
448        let mut bindings_includes: Vec<(PathBuf, Span)> = Vec::new();
449        let mut targets: Vec<TargetBinding> = Vec::new();
450
451        loop {
452            let t = match self.peek() {
453                Ok(t) => t,
454                Err(e) => {
455                    errors.push(e);
456                    break;
457                }
458            };
459            match &t.tok {
460                Tok::Eof => break,
461                Tok::Ident(name) if name == "include" => {
462                    self.next().ok();
463                    match self.expect_string() {
464                        Ok((s, span)) => {
465                            let p = PathBuf::from(&s);
466                            if s.ends_with(".bindings.chipi") {
467                                bindings_includes.push((p, span));
468                            } else if s.ends_with(".chipi") {
469                                spec_includes.push((p, span));
470                            } else {
471                                errors.push(Error::new(
472                                    ErrorKind::BindingsParse(format!(
473                                        "include path '{}' must end in .chipi or .bindings.chipi",
474                                        s
475                                    )),
476                                    span,
477                                ));
478                            }
479                        }
480                        Err(e) => errors.push(e),
481                    }
482                }
483                Tok::Ident(name) if name == "target" => match self.parse_target() {
484                    Ok(t) => targets.push(t),
485                    Err(e) => errors.push(e),
486                },
487                _ => {
488                    let t = self.next().unwrap();
489                    errors.push(Error::new(
490                        ErrorKind::BindingsParse(format!(
491                            "expected 'include' or 'target' at top level, got {:?}",
492                            t.tok
493                        )),
494                        t.span,
495                    ));
496                }
497            }
498        }
499
500        if errors.is_empty() {
501            Ok(BindingsFile {
502                path: self.file_path.clone(),
503                spec_includes,
504                bindings_includes,
505                targets,
506            })
507        } else {
508            Err(errors)
509        }
510    }
511
512    fn parse_target(&mut self) -> Result<TargetBinding, Error> {
513        // Consume 'target'
514        let target_tok = self.next()?;
515        let span = target_tok.span;
516        let (kind_name, kind_span) = self.expect_ident()?;
517        let kind = match kind_name.as_str() {
518            "rust" => TargetKind::Rust,
519            "cpp" | "c++" => TargetKind::Cpp,
520            "ida" => TargetKind::Ida,
521            "binja" => TargetKind::Binja,
522            other => {
523                return Err(Error::new(
524                    ErrorKind::UnknownTargetKind(other.to_string()),
525                    kind_span,
526                ));
527            }
528        };
529        self.expect_lbrace()?;
530
531        let mut binding = TargetBinding::empty(kind, span);
532
533        loop {
534            let t = self.peek_clone()?;
535            match &t.tok {
536                Tok::RBrace => {
537                    self.next()?;
538                    break;
539                }
540                Tok::Eof => {
541                    return Err(Error::new(
542                        ErrorKind::BindingsParse(
543                            "unexpected end of file inside target block".to_string(),
544                        ),
545                        t.span.clone(),
546                    ));
547                }
548                Tok::Ident(name) => match (kind, name.as_str()) {
549                    (TargetKind::Rust, "decoder") => {
550                        let d = self.parse_decoder_block()?;
551                        binding.rust_decoders.push(d);
552                    }
553                    (TargetKind::Rust, "dispatch") => {
554                        let d = self.parse_dispatch_block()?;
555                        binding.rust_dispatches.push(d);
556                    }
557                    (TargetKind::Cpp, "decoder") => {
558                        let d = self.parse_decoder_block()?;
559                        binding.cpp_decoders.push(d);
560                    }
561                    (TargetKind::Ida, "processor") => {
562                        let p = self.parse_processor_block()?;
563                        binding.ida_processors.push(p);
564                    }
565                    (TargetKind::Binja, "architecture") => {
566                        let a = self.parse_architecture_block()?;
567                        binding.binja_architectures.push(a);
568                    }
569                    _ => {
570                        let t = self.next()?;
571                        return Err(Error::new(
572                            ErrorKind::BindingsParse(format!(
573                                "unexpected '{}' inside target {}",
574                                name,
575                                kind.name()
576                            )),
577                            t.span,
578                        ));
579                    }
580                },
581                other => {
582                    let t = self.next()?;
583                    return Err(Error::new(
584                        ErrorKind::BindingsParse(format!(
585                            "unexpected token {:?} inside target block",
586                            other
587                        )),
588                        t.span,
589                    ));
590                }
591            }
592        }
593
594        Ok(binding)
595    }
596
597    fn parse_decoder_block(&mut self) -> Result<DecoderBinding, Error> {
598        // Consume 'decoder'
599        self.next()?;
600        let (name, span) = self.expect_ident()?;
601        self.expect_lbrace()?;
602
603        let mut output: Option<String> = None;
604        let mut type_map: BTreeMap<String, String> = BTreeMap::new();
605        let mut subdecoders: Vec<DecoderBinding> = Vec::new();
606        let mut cpp_namespace: Option<String> = None;
607        let mut cpp_guard_style: Option<String> = None;
608        let mut cpp_includes: Vec<String> = Vec::new();
609
610        loop {
611            let t = self.peek_clone()?;
612            match &t.tok {
613                Tok::RBrace => {
614                    self.next()?;
615                    break;
616                }
617                Tok::Eof => {
618                    return Err(Error::new(
619                        ErrorKind::BindingsParse(
620                            "unexpected end of file inside decoder block".to_string(),
621                        ),
622                        t.span.clone(),
623                    ));
624                }
625                Tok::Ident(name) => {
626                    let name = name.clone();
627                    match name.as_str() {
628                        "output" => {
629                            self.next()?;
630                            let (s, _) = self.expect_string()?;
631                            output = Some(s);
632                        }
633                        "type" => {
634                            self.next()?;
635                            let (lhs, _) = self.expect_ident()?;
636                            // expect '='
637                            let eq = self.next()?;
638                            if !matches!(eq.tok, Tok::Eq) {
639                                return Err(Error::new(
640                                    ErrorKind::BindingsParse(
641                                        "expected '=' in type alias".to_string(),
642                                    ),
643                                    eq.span,
644                                ));
645                            }
646                            let (rhs, _) = self.expect_ident()?;
647                            type_map.insert(lhs, rhs);
648                        }
649                        "subdecoder" => {
650                            let sd = self.parse_decoder_block()?;
651                            subdecoders.push(sd);
652                        }
653                        "namespace" => {
654                            self.next()?;
655                            let (s, _) = self.expect_string()?;
656                            cpp_namespace = Some(s);
657                        }
658                        "guard_style" => {
659                            self.next()?;
660                            let (s, _) = self.expect_ident()?;
661                            cpp_guard_style = Some(s);
662                        }
663                        "includes" => {
664                            self.next()?;
665                            cpp_includes = self.parse_string_block()?;
666                        }
667                        other => {
668                            let t = self.next()?;
669                            return Err(Error::new(
670                                ErrorKind::BindingsParse(format!(
671                                    "unexpected '{}' inside decoder block",
672                                    other
673                                )),
674                                t.span,
675                            ));
676                        }
677                    }
678                }
679                _ => {
680                    let t = self.next()?;
681                    return Err(Error::new(
682                        ErrorKind::BindingsParse(format!(
683                            "unexpected token {:?} inside decoder block",
684                            t.tok
685                        )),
686                        t.span,
687                    ));
688                }
689            }
690        }
691
692        let output = output.ok_or_else(|| {
693            Error::new(
694                ErrorKind::MissingBindingsField {
695                    block: format!("decoder {}", name),
696                    field: "output".to_string(),
697                },
698                span.clone(),
699            )
700        })?;
701
702        Ok(DecoderBinding {
703            decoder_name: name,
704            span,
705            output,
706            type_map,
707            subdecoders,
708            cpp_namespace,
709            cpp_guard_style,
710            cpp_includes,
711        })
712    }
713
714    fn parse_dispatch_block(&mut self) -> Result<DispatchBinding, Error> {
715        // Consume 'dispatch' (or 'subdispatch'). The caller handles either.
716        self.next()?;
717        let (name, span) = self.expect_ident()?;
718        self.expect_lbrace()?;
719
720        let mut output: Option<String> = None;
721        let mut context: Option<String> = None;
722        let mut handlers: Option<String> = None;
723        let mut strategy: Option<Dispatch> = None;
724        let mut invalid_handler: Option<String> = None;
725        let mut instruction_type: Option<InstructionTypeBinding> = None;
726        let mut handler_groups: Vec<HandlerBinding> = Vec::new();
727        let mut subdispatches: Vec<DispatchBinding> = Vec::new();
728
729        loop {
730            let t = self.peek_clone()?;
731            match &t.tok {
732                Tok::RBrace => {
733                    self.next()?;
734                    break;
735                }
736                Tok::Eof => {
737                    return Err(Error::new(
738                        ErrorKind::BindingsParse(
739                            "unexpected end of file inside dispatch block".to_string(),
740                        ),
741                        t.span.clone(),
742                    ));
743                }
744                Tok::Ident(name) => {
745                    let name = name.clone();
746                    match name.as_str() {
747                        "output" => {
748                            self.next()?;
749                            let (s, _) = self.expect_string()?;
750                            output = Some(s);
751                        }
752                        "context" => {
753                            self.next()?;
754                            let (s, _) = self.expect_ident()?;
755                            context = Some(s);
756                        }
757                        "handlers" => {
758                            self.next()?;
759                            let (s, _) = self.expect_ident()?;
760                            handlers = Some(s);
761                        }
762                        "strategy" => {
763                            self.next()?;
764                            let (s, span) = self.expect_ident()?;
765                            strategy = Some(parse_strategy(&s, &span)?);
766                        }
767                        "invalid_handler" => {
768                            self.next()?;
769                            let (s, _) = self.expect_ident()?;
770                            invalid_handler = Some(s);
771                        }
772                        "instruction_type" => {
773                            self.next()?;
774                            let (path, _) = self.expect_ident()?;
775                            // Optional `{ output "..." }`
776                            let next = self.peek()?;
777                            if matches!(next.tok, Tok::LBrace) {
778                                self.next()?;
779                                let mut inner_out: Option<String> = None;
780                                loop {
781                                    let t = self.peek_clone()?;
782                                    match &t.tok {
783                                        Tok::RBrace => {
784                                            self.next()?;
785                                            break;
786                                        }
787                                        Tok::Ident(n) if n == "output" => {
788                                            self.next()?;
789                                            let (s, _) = self.expect_string()?;
790                                            inner_out = Some(s);
791                                        }
792                                        _ => {
793                                            let t = self.next()?;
794                                            return Err(Error::new(
795                                                ErrorKind::BindingsParse(format!(
796                                                    "unexpected token {:?} inside instruction_type block",
797                                                    t.tok
798                                                )),
799                                                t.span,
800                                            ));
801                                        }
802                                    }
803                                }
804                                instruction_type = Some(InstructionTypeBinding {
805                                    type_path: path,
806                                    output: inner_out,
807                                });
808                            } else {
809                                instruction_type = Some(InstructionTypeBinding {
810                                    type_path: path,
811                                    output: None,
812                                });
813                            }
814                        }
815                        "handler" => {
816                            let group = self.parse_handler_block()?;
817                            handler_groups.push(group);
818                        }
819                        "subdispatch" => {
820                            let sd = self.parse_dispatch_block()?;
821                            subdispatches.push(sd);
822                        }
823                        other => {
824                            let t = self.next()?;
825                            return Err(Error::new(
826                                ErrorKind::BindingsParse(format!(
827                                    "unexpected '{}' inside dispatch block",
828                                    other
829                                )),
830                                t.span,
831                            ));
832                        }
833                    }
834                }
835                _ => {
836                    let t = self.next()?;
837                    return Err(Error::new(
838                        ErrorKind::BindingsParse(format!(
839                            "unexpected token {:?} inside dispatch block",
840                            t.tok
841                        )),
842                        t.span,
843                    ));
844                }
845            }
846        }
847
848        Ok(DispatchBinding {
849            decoder_name: name,
850            span,
851            output,
852            context,
853            handlers,
854            strategy,
855            invalid_handler,
856            instruction_type,
857            handler_groups,
858            subdispatches,
859        })
860    }
861
862    fn parse_handler_block(&mut self) -> Result<HandlerBinding, Error> {
863        // Consume 'handler'
864        self.next()?;
865        let (handler_name, span) = self.expect_ident()?;
866
867        // Optional `<const OP>` generic params
868        let mut generic_params: Vec<String> = Vec::new();
869        let next = self.peek()?;
870        if matches!(next.tok, Tok::LAngle) {
871            self.next()?;
872            loop {
873                let t = self.peek_clone()?;
874                match &t.tok {
875                    Tok::RAngle => {
876                        self.next()?;
877                        break;
878                    }
879                    Tok::Ident(_) => {
880                        // Allow chained idents like `const OP` (two tokens).
881                        // We collect them separated by spaces.
882                        let mut parts: Vec<String> = Vec::new();
883                        loop {
884                            let t = self.peek_clone()?;
885                            match &t.tok {
886                                Tok::Ident(s) => {
887                                    let s = s.clone();
888                                    self.next()?;
889                                    parts.push(s);
890                                }
891                                Tok::Comma => {
892                                    self.next()?;
893                                    break;
894                                }
895                                Tok::RAngle => break,
896                                other => {
897                                    let t = self.next()?;
898                                    return Err(Error::new(
899                                        ErrorKind::BindingsParse(format!(
900                                            "unexpected token {:?} in generic params",
901                                            other
902                                        )),
903                                        t.span,
904                                    ));
905                                }
906                            }
907                        }
908                        if !parts.is_empty() {
909                            generic_params.push(parts.join(" "));
910                        }
911                    }
912                    _ => {
913                        let t = self.next()?;
914                        return Err(Error::new(
915                            ErrorKind::BindingsParse(format!(
916                                "unexpected token {:?} in generic params",
917                                t.tok
918                            )),
919                            t.span,
920                        ));
921                    }
922                }
923            }
924        }
925
926        self.expect_lbrace()?;
927        let mut instructions: Vec<(String, Span)> = Vec::new();
928        loop {
929            let t = self.peek_clone()?;
930            match &t.tok {
931                Tok::RBrace => {
932                    self.next()?;
933                    break;
934                }
935                Tok::Comma => {
936                    self.next()?;
937                }
938                Tok::Ident(name) => {
939                    let name = name.clone();
940                    let t = self.next()?;
941                    instructions.push((name, t.span));
942                }
943                other => {
944                    let t = self.next()?;
945                    return Err(Error::new(
946                        ErrorKind::BindingsParse(format!(
947                            "unexpected token {:?} inside handler block",
948                            other
949                        )),
950                        t.span,
951                    ));
952                }
953            }
954        }
955
956        Ok(HandlerBinding {
957            handler_name,
958            generic_params,
959            instructions,
960            span,
961        })
962    }
963
964    fn parse_processor_block(&mut self) -> Result<IdaProcessorBinding, Error> {
965        self.next()?; // 'processor'
966        let (name, span) = self.expect_ident()?;
967        self.expect_lbrace()?;
968
969        let mut output: Option<String> = None;
970        let mut p_name: Option<String> = None;
971        let mut long_name: Option<String> = None;
972        let mut id: Option<u64> = None;
973        let mut address_size: Option<u32> = None;
974        let mut bytes_per_unit: Option<u32> = None;
975        let mut registers: Vec<String> = Vec::new();
976        let mut segment_registers: Vec<(String, Span)> = Vec::new();
977        let mut flow = IdaFlowBinding::default();
978
979        loop {
980            let t = self.peek_clone()?;
981            match &t.tok {
982                Tok::RBrace => {
983                    self.next()?;
984                    break;
985                }
986                Tok::Eof => {
987                    return Err(Error::new(
988                        ErrorKind::BindingsParse(
989                            "unexpected end of file inside processor block".to_string(),
990                        ),
991                        t.span.clone(),
992                    ));
993                }
994                Tok::Ident(name) => {
995                    let name = name.clone();
996                    match name.as_str() {
997                        "output" => {
998                            self.next()?;
999                            let (s, _) = self.expect_string()?;
1000                            output = Some(s);
1001                        }
1002                        "name" => {
1003                            self.next()?;
1004                            let (s, _) = self.expect_string()?;
1005                            p_name = Some(s);
1006                        }
1007                        "long_name" => {
1008                            self.next()?;
1009                            let (s, _) = self.expect_string()?;
1010                            long_name = Some(s);
1011                        }
1012                        "id" => {
1013                            self.next()?;
1014                            let (n, _) = self.expect_number()?;
1015                            id = Some(n);
1016                        }
1017                        "address_size" => {
1018                            self.next()?;
1019                            let (n, _) = self.expect_number()?;
1020                            address_size = Some(n as u32);
1021                        }
1022                        "bytes_per_unit" => {
1023                            self.next()?;
1024                            let (n, _) = self.expect_number()?;
1025                            bytes_per_unit = Some(n as u32);
1026                        }
1027                        "registers" => {
1028                            self.next()?;
1029                            registers = self.parse_ident_block()?;
1030                        }
1031                        "segment_registers" => {
1032                            self.next()?;
1033                            segment_registers = self.parse_ident_block_with_spans()?;
1034                        }
1035                        "flow" => {
1036                            self.next()?;
1037                            flow = self.parse_flow_block()?;
1038                        }
1039                        other => {
1040                            let t = self.next()?;
1041                            return Err(Error::new(
1042                                ErrorKind::BindingsParse(format!(
1043                                    "unexpected '{}' inside processor block",
1044                                    other
1045                                )),
1046                                t.span,
1047                            ));
1048                        }
1049                    }
1050                }
1051                _ => {
1052                    let t = self.next()?;
1053                    return Err(Error::new(
1054                        ErrorKind::BindingsParse(format!(
1055                            "unexpected token {:?} inside processor block",
1056                            t.tok
1057                        )),
1058                        t.span,
1059                    ));
1060                }
1061            }
1062        }
1063
1064        Ok(IdaProcessorBinding {
1065            decoder_name: name,
1066            span,
1067            output,
1068            name: p_name,
1069            long_name,
1070            id,
1071            address_size,
1072            bytes_per_unit,
1073            registers,
1074            segment_registers,
1075            flow,
1076        })
1077    }
1078
1079    fn parse_architecture_block(&mut self) -> Result<BinjaArchitectureBinding, Error> {
1080        self.next()?; // 'architecture'
1081        let (name, span) = self.expect_ident()?;
1082        self.expect_lbrace()?;
1083
1084        let mut output: Option<String> = None;
1085        let mut a_name: Option<String> = None;
1086        let mut address_size: Option<u32> = None;
1087        let mut default_int_size: Option<u32> = None;
1088        let mut endianness: Option<(String, Span)> = None;
1089        let mut registers: Vec<String> = Vec::new();
1090
1091        loop {
1092            let t = self.peek_clone()?;
1093            match &t.tok {
1094                Tok::RBrace => {
1095                    self.next()?;
1096                    break;
1097                }
1098                Tok::Eof => {
1099                    return Err(Error::new(
1100                        ErrorKind::BindingsParse(
1101                            "unexpected end of file inside architecture block".to_string(),
1102                        ),
1103                        t.span.clone(),
1104                    ));
1105                }
1106                Tok::Ident(name) => {
1107                    let name = name.clone();
1108                    match name.as_str() {
1109                        "output" => {
1110                            self.next()?;
1111                            let (s, _) = self.expect_string()?;
1112                            output = Some(s);
1113                        }
1114                        "name" => {
1115                            self.next()?;
1116                            let (s, _) = self.expect_string()?;
1117                            a_name = Some(s);
1118                        }
1119                        "address_size" => {
1120                            self.next()?;
1121                            let (n, _) = self.expect_number()?;
1122                            address_size = Some(n as u32);
1123                        }
1124                        "default_int_size" => {
1125                            self.next()?;
1126                            let (n, _) = self.expect_number()?;
1127                            default_int_size = Some(n as u32);
1128                        }
1129                        "endianness" => {
1130                            self.next()?;
1131                            let (s, span) = self.expect_ident()?;
1132                            endianness = Some((s, span));
1133                        }
1134                        "registers" => {
1135                            self.next()?;
1136                            registers = self.parse_ident_block()?;
1137                        }
1138                        other => {
1139                            let t = self.next()?;
1140                            return Err(Error::new(
1141                                ErrorKind::BindingsParse(format!(
1142                                    "unexpected '{}' inside architecture block",
1143                                    other
1144                                )),
1145                                t.span,
1146                            ));
1147                        }
1148                    }
1149                }
1150                _ => {
1151                    let t = self.next()?;
1152                    return Err(Error::new(
1153                        ErrorKind::BindingsParse(format!(
1154                            "unexpected token {:?} inside architecture block",
1155                            t.tok
1156                        )),
1157                        t.span,
1158                    ));
1159                }
1160            }
1161        }
1162
1163        Ok(BinjaArchitectureBinding {
1164            decoder_name: name,
1165            span,
1166            output,
1167            name: a_name,
1168            address_size,
1169            default_int_size,
1170            endianness,
1171            registers,
1172        })
1173    }
1174
1175    fn parse_ident_block(&mut self) -> Result<Vec<String>, Error> {
1176        let pairs = self.parse_ident_block_with_spans()?;
1177        Ok(pairs.into_iter().map(|(s, _)| s).collect())
1178    }
1179
1180    fn parse_string_block(&mut self) -> Result<Vec<String>, Error> {
1181        self.expect_lbrace()?;
1182        let mut out = Vec::new();
1183        loop {
1184            let t = self.peek_clone()?;
1185            match &t.tok {
1186                Tok::RBrace => {
1187                    self.next()?;
1188                    break;
1189                }
1190                Tok::Comma => {
1191                    self.next()?;
1192                }
1193                Tok::Str(_) => {
1194                    let t = self.next()?;
1195                    if let Tok::Str(s) = t.tok {
1196                        out.push(s);
1197                    }
1198                }
1199                other => {
1200                    let t = self.next()?;
1201                    return Err(Error::new(
1202                        ErrorKind::BindingsParse(format!(
1203                            "expected string literal, got {:?}",
1204                            other
1205                        )),
1206                        t.span,
1207                    ));
1208                }
1209            }
1210        }
1211        Ok(out)
1212    }
1213
1214    fn parse_ident_block_with_spans(&mut self) -> Result<Vec<(String, Span)>, Error> {
1215        self.expect_lbrace()?;
1216        let mut out = Vec::new();
1217        loop {
1218            let t = self.peek_clone()?;
1219            match &t.tok {
1220                Tok::RBrace => {
1221                    self.next()?;
1222                    break;
1223                }
1224                Tok::Comma => {
1225                    self.next()?;
1226                }
1227                Tok::Ident(_) => {
1228                    let t = self.next()?;
1229                    if let Tok::Ident(s) = t.tok {
1230                        out.push((s, t.span));
1231                    }
1232                }
1233                other => {
1234                    let t = self.next()?;
1235                    return Err(Error::new(
1236                        ErrorKind::BindingsParse(format!("expected identifier, got {:?}", other)),
1237                        t.span,
1238                    ));
1239                }
1240            }
1241        }
1242        Ok(out)
1243    }
1244
1245    fn parse_flow_block(&mut self) -> Result<IdaFlowBinding, Error> {
1246        self.expect_lbrace()?;
1247        let mut flow = IdaFlowBinding::default();
1248        loop {
1249            let t = self.peek_clone()?;
1250            match &t.tok {
1251                Tok::RBrace => {
1252                    self.next()?;
1253                    break;
1254                }
1255                Tok::Ident(name) => {
1256                    let name = name.clone();
1257                    match name.as_str() {
1258                        "calls" => {
1259                            self.next()?;
1260                            flow.calls = self.parse_ident_block_with_spans()?;
1261                        }
1262                        "returns" => {
1263                            self.next()?;
1264                            flow.returns = self.parse_ident_block_with_spans()?;
1265                        }
1266                        "stops" => {
1267                            self.next()?;
1268                            flow.stops = self.parse_ident_block_with_spans()?;
1269                        }
1270                        other => {
1271                            let t = self.next()?;
1272                            return Err(Error::new(
1273                                ErrorKind::BindingsParse(format!("unknown flow key '{}'", other)),
1274                                t.span,
1275                            ));
1276                        }
1277                    }
1278                }
1279                _ => {
1280                    let t = self.next()?;
1281                    return Err(Error::new(
1282                        ErrorKind::BindingsParse(format!(
1283                            "unexpected token {:?} inside flow block",
1284                            t.tok
1285                        )),
1286                        t.span,
1287                    ));
1288                }
1289            }
1290        }
1291        Ok(flow)
1292    }
1293}
1294
1295fn parse_strategy(s: &str, span: &Span) -> Result<Dispatch, Error> {
1296    match s {
1297        "fn_ptr_lut" => Ok(Dispatch::FnPtrLut),
1298        "jump_table" => Ok(Dispatch::JumpTable),
1299        "flat_lut" => Ok(Dispatch::FlatLut),
1300        "flat_match" => Ok(Dispatch::FlatMatch),
1301        other => Err(Error::new(
1302            ErrorKind::InvalidStrategy(other.to_string()),
1303            span.clone(),
1304        )),
1305    }
1306}