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        let mut handler_consts: Vec<String> = Vec::new();
729
730        loop {
731            let t = self.peek_clone()?;
732            match &t.tok {
733                Tok::RBrace => {
734                    self.next()?;
735                    break;
736                }
737                Tok::Eof => {
738                    return Err(Error::new(
739                        ErrorKind::BindingsParse(
740                            "unexpected end of file inside dispatch block".to_string(),
741                        ),
742                        t.span.clone(),
743                    ));
744                }
745                Tok::Ident(name) => {
746                    let name = name.clone();
747                    match name.as_str() {
748                        "output" => {
749                            self.next()?;
750                            let (s, _) = self.expect_string()?;
751                            output = Some(s);
752                        }
753                        "context" => {
754                            self.next()?;
755                            let (s, _) = self.expect_ident()?;
756                            context = Some(s);
757                        }
758                        "handlers" => {
759                            self.next()?;
760                            let (s, _) = self.expect_ident()?;
761                            handlers = Some(s);
762                        }
763                        "strategy" => {
764                            self.next()?;
765                            let (s, span) = self.expect_ident()?;
766                            strategy = Some(parse_strategy(&s, &span)?);
767                        }
768                        "invalid_handler" => {
769                            self.next()?;
770                            let (s, _) = self.expect_ident()?;
771                            invalid_handler = Some(s);
772                        }
773                        "handler_const" => {
774                            self.next()?;
775                            let (s, _) = self.expect_ident()?;
776                            handler_consts.push(s);
777                        }
778                        "instruction_type" => {
779                            self.next()?;
780                            let (path, _) = self.expect_ident()?;
781                            // Optional `{ output "..." }`
782                            let next = self.peek()?;
783                            if matches!(next.tok, Tok::LBrace) {
784                                self.next()?;
785                                let mut inner_out: Option<String> = None;
786                                loop {
787                                    let t = self.peek_clone()?;
788                                    match &t.tok {
789                                        Tok::RBrace => {
790                                            self.next()?;
791                                            break;
792                                        }
793                                        Tok::Ident(n) if n == "output" => {
794                                            self.next()?;
795                                            let (s, _) = self.expect_string()?;
796                                            inner_out = Some(s);
797                                        }
798                                        _ => {
799                                            let t = self.next()?;
800                                            return Err(Error::new(
801                                                ErrorKind::BindingsParse(format!(
802                                                    "unexpected token {:?} inside instruction_type block",
803                                                    t.tok
804                                                )),
805                                                t.span,
806                                            ));
807                                        }
808                                    }
809                                }
810                                instruction_type = Some(InstructionTypeBinding {
811                                    type_path: path,
812                                    output: inner_out,
813                                });
814                            } else {
815                                instruction_type = Some(InstructionTypeBinding {
816                                    type_path: path,
817                                    output: None,
818                                });
819                            }
820                        }
821                        "handler" => {
822                            let group = self.parse_handler_block()?;
823                            handler_groups.push(group);
824                        }
825                        "subdispatch" => {
826                            let sd = self.parse_dispatch_block()?;
827                            subdispatches.push(sd);
828                        }
829                        other => {
830                            let t = self.next()?;
831                            return Err(Error::new(
832                                ErrorKind::BindingsParse(format!(
833                                    "unexpected '{}' inside dispatch block",
834                                    other
835                                )),
836                                t.span,
837                            ));
838                        }
839                    }
840                }
841                _ => {
842                    let t = self.next()?;
843                    return Err(Error::new(
844                        ErrorKind::BindingsParse(format!(
845                            "unexpected token {:?} inside dispatch block",
846                            t.tok
847                        )),
848                        t.span,
849                    ));
850                }
851            }
852        }
853
854        Ok(DispatchBinding {
855            decoder_name: name,
856            span,
857            output,
858            context,
859            handlers,
860            strategy,
861            invalid_handler,
862            instruction_type,
863            handler_groups,
864            subdispatches,
865            handler_consts,
866        })
867    }
868
869    fn parse_handler_block(&mut self) -> Result<HandlerBinding, Error> {
870        // Consume 'handler'
871        self.next()?;
872        let (handler_name, span) = self.expect_ident()?;
873
874        self.expect_lbrace()?;
875        let mut instructions: Vec<(String, Span)> = Vec::new();
876        loop {
877            let t = self.peek_clone()?;
878            match &t.tok {
879                Tok::RBrace => {
880                    self.next()?;
881                    break;
882                }
883                Tok::Comma => {
884                    self.next()?;
885                }
886                Tok::Ident(name) => {
887                    let name = name.clone();
888                    let t = self.next()?;
889                    instructions.push((name, t.span));
890                }
891                other => {
892                    let t = self.next()?;
893                    return Err(Error::new(
894                        ErrorKind::BindingsParse(format!(
895                            "unexpected token {:?} inside handler block",
896                            other
897                        )),
898                        t.span,
899                    ));
900                }
901            }
902        }
903
904        Ok(HandlerBinding {
905            handler_name,
906            instructions,
907            span,
908        })
909    }
910
911    fn parse_processor_block(&mut self) -> Result<IdaProcessorBinding, Error> {
912        self.next()?; // 'processor'
913        let (name, span) = self.expect_ident()?;
914        self.expect_lbrace()?;
915
916        let mut output: Option<String> = None;
917        let mut p_name: Option<String> = None;
918        let mut long_name: Option<String> = None;
919        let mut id: Option<u64> = None;
920        let mut address_size: Option<u32> = None;
921        let mut bytes_per_unit: Option<u32> = None;
922        let mut registers: Vec<String> = Vec::new();
923        let mut segment_registers: Vec<(String, Span)> = Vec::new();
924        let mut flow = IdaFlowBinding::default();
925
926        loop {
927            let t = self.peek_clone()?;
928            match &t.tok {
929                Tok::RBrace => {
930                    self.next()?;
931                    break;
932                }
933                Tok::Eof => {
934                    return Err(Error::new(
935                        ErrorKind::BindingsParse(
936                            "unexpected end of file inside processor block".to_string(),
937                        ),
938                        t.span.clone(),
939                    ));
940                }
941                Tok::Ident(name) => {
942                    let name = name.clone();
943                    match name.as_str() {
944                        "output" => {
945                            self.next()?;
946                            let (s, _) = self.expect_string()?;
947                            output = Some(s);
948                        }
949                        "name" => {
950                            self.next()?;
951                            let (s, _) = self.expect_string()?;
952                            p_name = Some(s);
953                        }
954                        "long_name" => {
955                            self.next()?;
956                            let (s, _) = self.expect_string()?;
957                            long_name = Some(s);
958                        }
959                        "id" => {
960                            self.next()?;
961                            let (n, _) = self.expect_number()?;
962                            id = Some(n);
963                        }
964                        "address_size" => {
965                            self.next()?;
966                            let (n, _) = self.expect_number()?;
967                            address_size = Some(n as u32);
968                        }
969                        "bytes_per_unit" => {
970                            self.next()?;
971                            let (n, _) = self.expect_number()?;
972                            bytes_per_unit = Some(n as u32);
973                        }
974                        "registers" => {
975                            self.next()?;
976                            registers = self.parse_ident_block()?;
977                        }
978                        "segment_registers" => {
979                            self.next()?;
980                            segment_registers = self.parse_ident_block_with_spans()?;
981                        }
982                        "flow" => {
983                            self.next()?;
984                            flow = self.parse_flow_block()?;
985                        }
986                        other => {
987                            let t = self.next()?;
988                            return Err(Error::new(
989                                ErrorKind::BindingsParse(format!(
990                                    "unexpected '{}' inside processor block",
991                                    other
992                                )),
993                                t.span,
994                            ));
995                        }
996                    }
997                }
998                _ => {
999                    let t = self.next()?;
1000                    return Err(Error::new(
1001                        ErrorKind::BindingsParse(format!(
1002                            "unexpected token {:?} inside processor block",
1003                            t.tok
1004                        )),
1005                        t.span,
1006                    ));
1007                }
1008            }
1009        }
1010
1011        Ok(IdaProcessorBinding {
1012            decoder_name: name,
1013            span,
1014            output,
1015            name: p_name,
1016            long_name,
1017            id,
1018            address_size,
1019            bytes_per_unit,
1020            registers,
1021            segment_registers,
1022            flow,
1023        })
1024    }
1025
1026    fn parse_architecture_block(&mut self) -> Result<BinjaArchitectureBinding, Error> {
1027        self.next()?; // 'architecture'
1028        let (name, span) = self.expect_ident()?;
1029        self.expect_lbrace()?;
1030
1031        let mut output: Option<String> = None;
1032        let mut a_name: Option<String> = None;
1033        let mut address_size: Option<u32> = None;
1034        let mut default_int_size: Option<u32> = None;
1035        let mut endianness: Option<(String, Span)> = None;
1036        let mut registers: Vec<String> = Vec::new();
1037
1038        loop {
1039            let t = self.peek_clone()?;
1040            match &t.tok {
1041                Tok::RBrace => {
1042                    self.next()?;
1043                    break;
1044                }
1045                Tok::Eof => {
1046                    return Err(Error::new(
1047                        ErrorKind::BindingsParse(
1048                            "unexpected end of file inside architecture block".to_string(),
1049                        ),
1050                        t.span.clone(),
1051                    ));
1052                }
1053                Tok::Ident(name) => {
1054                    let name = name.clone();
1055                    match name.as_str() {
1056                        "output" => {
1057                            self.next()?;
1058                            let (s, _) = self.expect_string()?;
1059                            output = Some(s);
1060                        }
1061                        "name" => {
1062                            self.next()?;
1063                            let (s, _) = self.expect_string()?;
1064                            a_name = Some(s);
1065                        }
1066                        "address_size" => {
1067                            self.next()?;
1068                            let (n, _) = self.expect_number()?;
1069                            address_size = Some(n as u32);
1070                        }
1071                        "default_int_size" => {
1072                            self.next()?;
1073                            let (n, _) = self.expect_number()?;
1074                            default_int_size = Some(n as u32);
1075                        }
1076                        "endianness" => {
1077                            self.next()?;
1078                            let (s, span) = self.expect_ident()?;
1079                            endianness = Some((s, span));
1080                        }
1081                        "registers" => {
1082                            self.next()?;
1083                            registers = self.parse_ident_block()?;
1084                        }
1085                        other => {
1086                            let t = self.next()?;
1087                            return Err(Error::new(
1088                                ErrorKind::BindingsParse(format!(
1089                                    "unexpected '{}' inside architecture block",
1090                                    other
1091                                )),
1092                                t.span,
1093                            ));
1094                        }
1095                    }
1096                }
1097                _ => {
1098                    let t = self.next()?;
1099                    return Err(Error::new(
1100                        ErrorKind::BindingsParse(format!(
1101                            "unexpected token {:?} inside architecture block",
1102                            t.tok
1103                        )),
1104                        t.span,
1105                    ));
1106                }
1107            }
1108        }
1109
1110        Ok(BinjaArchitectureBinding {
1111            decoder_name: name,
1112            span,
1113            output,
1114            name: a_name,
1115            address_size,
1116            default_int_size,
1117            endianness,
1118            registers,
1119        })
1120    }
1121
1122    fn parse_ident_block(&mut self) -> Result<Vec<String>, Error> {
1123        let pairs = self.parse_ident_block_with_spans()?;
1124        Ok(pairs.into_iter().map(|(s, _)| s).collect())
1125    }
1126
1127    fn parse_string_block(&mut self) -> Result<Vec<String>, Error> {
1128        self.expect_lbrace()?;
1129        let mut out = Vec::new();
1130        loop {
1131            let t = self.peek_clone()?;
1132            match &t.tok {
1133                Tok::RBrace => {
1134                    self.next()?;
1135                    break;
1136                }
1137                Tok::Comma => {
1138                    self.next()?;
1139                }
1140                Tok::Str(_) => {
1141                    let t = self.next()?;
1142                    if let Tok::Str(s) = t.tok {
1143                        out.push(s);
1144                    }
1145                }
1146                other => {
1147                    let t = self.next()?;
1148                    return Err(Error::new(
1149                        ErrorKind::BindingsParse(format!(
1150                            "expected string literal, got {:?}",
1151                            other
1152                        )),
1153                        t.span,
1154                    ));
1155                }
1156            }
1157        }
1158        Ok(out)
1159    }
1160
1161    fn parse_ident_block_with_spans(&mut self) -> Result<Vec<(String, Span)>, Error> {
1162        self.expect_lbrace()?;
1163        let mut out = Vec::new();
1164        loop {
1165            let t = self.peek_clone()?;
1166            match &t.tok {
1167                Tok::RBrace => {
1168                    self.next()?;
1169                    break;
1170                }
1171                Tok::Comma => {
1172                    self.next()?;
1173                }
1174                Tok::Ident(_) => {
1175                    let t = self.next()?;
1176                    if let Tok::Ident(s) = t.tok {
1177                        out.push((s, t.span));
1178                    }
1179                }
1180                other => {
1181                    let t = self.next()?;
1182                    return Err(Error::new(
1183                        ErrorKind::BindingsParse(format!("expected identifier, got {:?}", other)),
1184                        t.span,
1185                    ));
1186                }
1187            }
1188        }
1189        Ok(out)
1190    }
1191
1192    fn parse_flow_block(&mut self) -> Result<IdaFlowBinding, Error> {
1193        self.expect_lbrace()?;
1194        let mut flow = IdaFlowBinding::default();
1195        loop {
1196            let t = self.peek_clone()?;
1197            match &t.tok {
1198                Tok::RBrace => {
1199                    self.next()?;
1200                    break;
1201                }
1202                Tok::Ident(name) => {
1203                    let name = name.clone();
1204                    match name.as_str() {
1205                        "calls" => {
1206                            self.next()?;
1207                            flow.calls = self.parse_ident_block_with_spans()?;
1208                        }
1209                        "returns" => {
1210                            self.next()?;
1211                            flow.returns = self.parse_ident_block_with_spans()?;
1212                        }
1213                        "stops" => {
1214                            self.next()?;
1215                            flow.stops = self.parse_ident_block_with_spans()?;
1216                        }
1217                        other => {
1218                            let t = self.next()?;
1219                            return Err(Error::new(
1220                                ErrorKind::BindingsParse(format!("unknown flow key '{}'", other)),
1221                                t.span,
1222                            ));
1223                        }
1224                    }
1225                }
1226                _ => {
1227                    let t = self.next()?;
1228                    return Err(Error::new(
1229                        ErrorKind::BindingsParse(format!(
1230                            "unexpected token {:?} inside flow block",
1231                            t.tok
1232                        )),
1233                        t.span,
1234                    ));
1235                }
1236            }
1237        }
1238        Ok(flow)
1239    }
1240}
1241
1242fn parse_strategy(s: &str, span: &Span) -> Result<Dispatch, Error> {
1243    match s {
1244        "fn_ptr_lut" => Ok(Dispatch::FnPtrLut),
1245        "jump_table" => Ok(Dispatch::JumpTable),
1246        "flat_lut" => Ok(Dispatch::FlatLut),
1247        "flat_match" => Ok(Dispatch::FlatMatch),
1248        other => Err(Error::new(
1249            ErrorKind::InvalidStrategy(other.to_string()),
1250            span.clone(),
1251        )),
1252    }
1253}