Skip to main content

bitwright/text/
parse.rs

1//! Parser for the expression syntax, with width inference.
2//!
3//! Parsing builds a flat, width-annotated tree first (children before parents; `let` bindings
4//! make it a DAG), infers every width by unification, and only then builds nodes through the
5//! canonicalizing constructors. Nesting is limited, so untrusted input cannot exhaust the stack.
6
7use std::collections::HashMap;
8
9use super::SyntaxError;
10use super::lex::{Tok, Token, lex};
11use crate::error::Error;
12use crate::expr::{Context, Expr};
13use crate::ops::{BinOp, CmpOpExt, UnOp};
14use crate::{BitVec, SymbolKey, Width};
15
16/// Options for [`Context::parse`].
17#[derive(Clone, Debug, Default)]
18#[non_exhaustive]
19pub struct ParseOptions {
20    /// Width for symbols and literals whose width cannot be inferred. `None` makes such an
21    /// expression an error.
22    pub default_width: Option<Width>,
23    /// Only resolve symbols that already exist in the context (never create new ones).
24    pub existing_symbols_only: bool,
25}
26
27impl ParseOptions {
28    /// Options with a default width.
29    pub fn width(w: Width) -> Self {
30        ParseOptions {
31            default_width: Some(w),
32            existing_symbols_only: false,
33        }
34    }
35
36    /// Sets [`existing_symbols_only`](Self::existing_symbols_only).
37    pub fn with_existing_symbols_only(mut self, yes: bool) -> Self {
38        self.existing_symbols_only = yes;
39        self
40    }
41}
42
43const MAX_DEPTH: u32 = 128;
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub(crate) enum Derived {
47    UMin,
48    UMax,
49    SMin,
50    SMax,
51    AndN,
52    OrN,
53    XNor,
54    Abs,
55    AddCarry,
56    SubBorrow,
57    SAddOverflow,
58    SSubOverflow,
59    AddSatU,
60    AddSatS,
61    SubSatU,
62    SubSatS,
63}
64
65#[derive(Clone, Debug)]
66enum Kind {
67    Lit(Vec<u64>),
68    /// `-<literal>`: range-checked as a signed value.
69    NegLit(Vec<u64>),
70    Bool(bool),
71    Sym(SymbolKey),
72    Un(UnOp, usize),
73    Bin(BinOp, usize, usize),
74    Cmp(CmpOpExt, usize, usize),
75    Zext(usize),
76    Sext(usize),
77    Extract(u16, usize),
78    Concat(usize, usize),
79    Select(usize, usize, usize),
80    Derived(Derived, usize, usize),
81    /// Output `k` of an extension operation on 1 to 3 arguments.
82    Ext(crate::ext::ExtId, u8, Vec<usize>),
83}
84
85struct PNode {
86    kind: Kind,
87    var: usize,
88    span: (usize, usize),
89}
90
91/// Union-find over width variables, each optionally fixed to a width.
92struct Widths {
93    parent: Vec<usize>,
94    value: Vec<Option<u16>>,
95}
96
97impl Widths {
98    fn fresh(&mut self) -> usize {
99        self.parent.push(self.parent.len());
100        self.value.push(None);
101        self.parent.len() - 1
102    }
103
104    fn find(&mut self, mut x: usize) -> usize {
105        while self.parent[x] != x {
106            self.parent[x] = self.parent[self.parent[x]];
107            x = self.parent[x];
108        }
109        x
110    }
111
112    fn get(&mut self, x: usize) -> Option<u16> {
113        let r = self.find(x);
114        self.value[r]
115    }
116
117    /// Returns false on a conflict.
118    fn unify(&mut self, a: usize, b: usize) -> bool {
119        let (ra, rb) = (self.find(a), self.find(b));
120        if ra == rb {
121            return true;
122        }
123        let v = match (self.value[ra], self.value[rb]) {
124            (Some(x), Some(y)) if x != y => return false,
125            (x, y) => x.or(y),
126        };
127        self.parent[rb] = ra;
128        self.value[ra] = v;
129        true
130    }
131
132    fn fix(&mut self, a: usize, w: u16) -> bool {
133        let r = self.find(a);
134        match self.value[r] {
135            Some(x) => x == w,
136            None => {
137                self.value[r] = Some(w);
138                true
139            }
140        }
141    }
142}
143
144struct Parser<'a> {
145    toks: Vec<Token>,
146    pos: usize,
147    nodes: Vec<PNode>,
148    widths: Widths,
149    lets: HashMap<LetKey, usize>,
150    sym_vars: HashMap<SymbolKey, usize>,
151    cx: &'a Context,
152    opts: &'a ParseOptions,
153    depth: u32,
154}
155
156#[derive(Clone, PartialEq, Eq, Hash)]
157enum LetKey {
158    Num(u32),
159    Name(String),
160}
161
162type PResult<T> = Result<T, SyntaxError>;
163
164impl<'a> Parser<'a> {
165    fn peek(&self) -> &Tok {
166        &self.toks[self.pos].tok
167    }
168
169    fn span(&self) -> (usize, usize) {
170        let t = &self.toks[self.pos];
171        (t.start, t.end)
172    }
173
174    fn bump(&mut self) -> Token {
175        let t = self.toks[self.pos].clone();
176        if self.pos + 1 < self.toks.len() {
177            self.pos += 1;
178        }
179        t
180    }
181
182    fn error<T>(&self, msg: &str) -> PResult<T> {
183        let (s, e) = self.span();
184        Err(SyntaxError::new(msg, s, e))
185    }
186
187    fn expect(&mut self, t: Tok, what: &str) -> PResult<Token> {
188        if *self.peek() == t {
189            Ok(self.bump())
190        } else {
191            self.error(&format!("expected {what}"))
192        }
193    }
194
195    fn node(&mut self, kind: Kind, span: (usize, usize)) -> usize {
196        let var = self.widths.fresh();
197        self.nodes.push(PNode { kind, var, span });
198        self.nodes.len() - 1
199    }
200
201    fn var(&self, n: usize) -> usize {
202        self.nodes[n].var
203    }
204
205    fn unify(&mut self, a: usize, b: usize, span: (usize, usize)) -> PResult<()> {
206        let (va, vb) = (self.var(a), self.var(b));
207        if self.widths.unify(va, vb) {
208            Ok(())
209        } else {
210            let (wa, wb) = (self.widths.get(va), self.widths.get(vb));
211            Err(SyntaxError::new(
212                &format!(
213                    "operand widths differ ({} vs {}); insert an explicit zext/sext/trunc",
214                    wa.unwrap_or(0),
215                    wb.unwrap_or(0)
216                ),
217                span.0,
218                span.1,
219            ))
220        }
221    }
222
223    fn fix(&mut self, n: usize, w: u16, span: (usize, usize)) -> PResult<()> {
224        let v = self.var(n);
225        if self.widths.fix(v, w) {
226            Ok(())
227        } else {
228            let have = self.widths.get(v).unwrap_or(0);
229            Err(SyntaxError::new(
230                &format!("width {w} conflicts with inferred width {have}"),
231                span.0,
232                span.1,
233            ))
234        }
235    }
236
237    fn enter(&mut self) -> PResult<()> {
238        self.depth += 1;
239        if self.depth > MAX_DEPTH {
240            return self.error("expression nested too deeply; use `let` bindings");
241        }
242        Ok(())
243    }
244
245    // ----- grammar --------------------------------------------------------------------------
246
247    fn top(&mut self) -> PResult<usize> {
248        while matches!(self.peek(), Tok::Ident(s) if s == "let") {
249            self.bump();
250            let key = match self.bump().tok {
251                Tok::LetName(k) => LetKey::Num(k),
252                Tok::Ident(s) if !super::is_reserved(&s) => LetKey::Name(s),
253                _ => return self.error("expected a name after `let`"),
254            };
255            self.expect(Tok::Assign, "`=`")?;
256            let e = self.expr()?;
257            self.expect(Tok::Semi, "`;`")?;
258            if self.lets.insert(key, e).is_some() {
259                return self.error("this name is already bound by an earlier `let`");
260            }
261        }
262        let e = self.expr()?;
263        if *self.peek() != Tok::Eof {
264            return self.error("unexpected input after expression");
265        }
266        Ok(e)
267    }
268
269    fn expr(&mut self) -> PResult<usize> {
270        self.enter()?;
271        let start = self.span().0;
272        let lhs = self.binary(0)?;
273        let op = match self.peek() {
274            Tok::Eq => CmpOpExt::Eq,
275            Tok::Ne => CmpOpExt::Ne,
276            Tok::Ult => CmpOpExt::Ult,
277            Tok::Ule => CmpOpExt::Ule,
278            Tok::Ugt => CmpOpExt::Ugt,
279            Tok::Uge => CmpOpExt::Uge,
280            Tok::Slt => CmpOpExt::Slt,
281            Tok::Sle => CmpOpExt::Sle,
282            Tok::Sgt => CmpOpExt::Sgt,
283            Tok::Sge => CmpOpExt::Sge,
284            _ => {
285                self.depth -= 1;
286                return Ok(lhs);
287            }
288        };
289        self.bump();
290        let rhs = self.binary(0)?;
291        let span = (start, self.toks[self.pos.saturating_sub(1)].end);
292        self.unify(lhs, rhs, span)?;
293        let n = self.node(Kind::Cmp(op, lhs, rhs), span);
294        self.fix(n, 1, span)?;
295        if matches!(
296            self.peek(),
297            Tok::Eq
298                | Tok::Ne
299                | Tok::Ult
300                | Tok::Ule
301                | Tok::Ugt
302                | Tok::Uge
303                | Tok::Slt
304                | Tok::Sle
305                | Tok::Sgt
306                | Tok::Sge
307        ) {
308            return self.error("comparisons do not chain; add parentheses");
309        }
310        self.depth -= 1;
311        Ok(n)
312    }
313
314    /// The binary operator at the cursor and its precedence (higher binds tighter).
315    fn binary_op(&self) -> Option<(BinOp, u8)> {
316        Some(match self.peek() {
317            Tok::Pipe => (BinOp::Or, 2),
318            Tok::Caret => (BinOp::Xor, 3),
319            Tok::Amp => (BinOp::And, 4),
320            Tok::Shl => (BinOp::Shl, 5),
321            Tok::LShr => (BinOp::LShr, 5),
322            Tok::AShr => (BinOp::AShr, 5),
323            Tok::Plus => (BinOp::Add, 6),
324            Tok::Minus => (BinOp::Sub, 6),
325            Tok::Star => (BinOp::Mul, 7),
326            _ => return None,
327        })
328    }
329
330    /// Precedence climbing over the left-associative binary operators.
331    fn binary(&mut self, min_prec: u8) -> PResult<usize> {
332        let start = self.span().0;
333        let mut lhs = self.unary()?;
334        while let Some((op, prec)) = self.binary_op() {
335            if prec < min_prec {
336                break;
337            }
338            self.bump();
339            let rhs = self.binary(prec + 1)?;
340            let span = (start, self.toks[self.pos.saturating_sub(1)].end);
341            self.unify(lhs, rhs, span)?;
342            let n = self.node(Kind::Bin(op, lhs, rhs), span);
343            self.unify(n, lhs, span)?;
344            lhs = n;
345        }
346        Ok(lhs)
347    }
348
349    fn unary(&mut self) -> PResult<usize> {
350        let op = match self.peek() {
351            Tok::Tilde => UnOp::Not,
352            Tok::Minus => UnOp::Neg,
353            _ => return self.postfix(),
354        };
355        self.enter()?;
356        let start = self.bump().start;
357        let a = self.unary()?;
358        let span = (start, self.toks[self.pos.saturating_sub(1)].end);
359        if op == UnOp::Neg
360            && a + 1 == self.nodes.len()
361            && let Kind::Lit(limbs) = &self.nodes[a].kind
362        {
363            self.nodes[a].kind = Kind::NegLit(limbs.clone());
364            self.nodes[a].span = span;
365            self.depth -= 1;
366            return Ok(a);
367        }
368        let n = self.node(Kind::Un(op, a), span);
369        self.unify(n, a, span)?;
370        self.depth -= 1;
371        Ok(n)
372    }
373
374    fn postfix(&mut self) -> PResult<usize> {
375        let e = self.primary()?;
376        if *self.peek() == Tok::Colon {
377            self.bump();
378            let span = self.span();
379            let w = self.width_literal()?;
380            self.fix(e, w, span)?;
381        }
382        Ok(e)
383    }
384
385    fn width_literal(&mut self) -> PResult<u16> {
386        let span = self.span();
387        match self.bump().tok {
388            Tok::Int(d, 10) => d
389                .parse::<u16>()
390                .ok()
391                .filter(|w| Width::new(*w).is_ok())
392                .ok_or_else(|| SyntaxError::new("width must be in 1..=512", span.0, span.1)),
393            _ => Err(SyntaxError::new("expected a decimal width", span.0, span.1)),
394        }
395    }
396
397    fn primary(&mut self) -> PResult<usize> {
398        let span = self.span();
399        let t = self.bump();
400        match t.tok {
401            Tok::Int(digits, radix) => {
402                let limbs = parse_limbs(&digits, radix)
403                    .ok_or_else(|| SyntaxError::new("literal exceeds 512 bits", span.0, span.1))?;
404                Ok(self.node(Kind::Lit(limbs), span))
405            }
406            Tok::LParen => {
407                let e = self.expr()?;
408                self.expect(Tok::RParen, "`)`")?;
409                Ok(e)
410            }
411            Tok::LetName(k) => self
412                .lets
413                .get(&LetKey::Num(k))
414                .copied()
415                .ok_or_else(|| SyntaxError::new(&format!("unbound name %{k}"), span.0, span.1)),
416            Tok::HashKey(k) => self.symbol(SymbolKey::U64(k), span),
417            Tok::FreshKey(k) => self.symbol(SymbolKey::Fresh(k), span),
418            Tok::Str(s) => self.symbol(SymbolKey::from(s), span),
419            Tok::Ext(name, k) => {
420                let op = self
421                    .cx
422                    .registry()
423                    .and_then(|r| r.id(&name))
424                    .ok_or_else(|| {
425                        SyntaxError::new(
426                            &format!("no extension operation `{name}` in this context"),
427                            span.0,
428                            span.1,
429                        )
430                    })?;
431                self.enter()?;
432                self.expect(Tok::LParen, "`(`")?;
433                let mut args = vec![self.expr()?];
434                while *self.peek() == Tok::Comma {
435                    self.bump();
436                    args.push(self.expr()?);
437                }
438                self.expect(Tok::RParen, "`)`")?;
439                self.depth -= 1;
440                let end = self.toks[self.pos.saturating_sub(1)].end;
441                if args.len() > crate::ext::MAX_ARGS {
442                    return Err(SyntaxError::new(
443                        &format!("`{name}` takes at most {} arguments", crate::ext::MAX_ARGS),
444                        span.0,
445                        end,
446                    ));
447                }
448                Ok(self.node(Kind::Ext(op, k, args), (span.0, end)))
449            }
450            Tok::Ident(name) => {
451                if name == "true" || name == "false" {
452                    let n = self.node(Kind::Bool(name == "true"), span);
453                    self.fix(n, 1, span)?;
454                    return Ok(n);
455                }
456                if let Some(&e) = self.lets.get(&LetKey::Name(name.clone())) {
457                    return Ok(e);
458                }
459                if super::FUNCTIONS.contains(&name.as_str()) {
460                    return self.call(&name, span);
461                }
462                if super::is_reserved(&name) {
463                    return Err(SyntaxError::new(
464                        &format!("`{name}` is reserved"),
465                        span.0,
466                        span.1,
467                    ));
468                }
469                self.symbol(SymbolKey::from(name), span)
470            }
471            _ => Err(SyntaxError::new("expected an expression", span.0, span.1)),
472        }
473    }
474
475    fn symbol(&mut self, key: SymbolKey, span: (usize, usize)) -> PResult<usize> {
476        let existing = self
477            .cx
478            .find_symbol(&key)
479            .and_then(|e| self.cx.width(e).ok());
480        if existing.is_none() && self.opts.existing_symbols_only {
481            return Err(SyntaxError::new(
482                &format!("unknown symbol {key}"),
483                span.0,
484                span.1,
485            ));
486        }
487        let n = self.node(Kind::Sym(key.clone()), span);
488        if let Some(&v) = self.sym_vars.get(&key) {
489            let nv = self.var(n);
490            if !self.widths.unify(nv, v) {
491                return Err(SyntaxError::new("symbol width conflict", span.0, span.1));
492            }
493        } else {
494            self.sym_vars.insert(key, self.var(n));
495        }
496        if let Some(w) = existing {
497            self.fix(n, w.bits(), span)?;
498        }
499        Ok(n)
500    }
501
502    fn generics(&mut self, count: usize) -> PResult<Vec<u16>> {
503        self.expect(Tok::LAngle, "`<`")?;
504        let mut out = Vec::new();
505        for k in 0..count {
506            if k > 0 {
507                self.expect(Tok::Comma, "`,`")?;
508            }
509            let span = self.span();
510            match self.bump().tok {
511                Tok::Int(d, 10) => out.push(
512                    d.parse::<u16>()
513                        .map_err(|_| SyntaxError::new("number too large", span.0, span.1))?,
514                ),
515                _ => return Err(SyntaxError::new("expected a number", span.0, span.1)),
516            }
517        }
518        self.expect(Tok::RAngle, "`>`")?;
519        Ok(out)
520    }
521
522    fn args(&mut self, count: usize) -> PResult<Vec<usize>> {
523        self.expect(Tok::LParen, "`(`")?;
524        let mut out = Vec::new();
525        for k in 0..count {
526            if k > 0 {
527                self.expect(Tok::Comma, "`,`")?;
528            }
529            out.push(self.expr()?);
530        }
531        self.expect(Tok::RParen, "`)`")?;
532        Ok(out)
533    }
534
535    fn call(&mut self, name: &str, start: (usize, usize)) -> PResult<usize> {
536        self.enter()?;
537        let un = |n: &str| {
538            Some(match n {
539                "popcnt" => UnOp::Popcnt,
540                "clz" => UnOp::Clz,
541                "ctz" => UnOp::Ctz,
542                "bswap" => UnOp::Bswap,
543                "bitrev" => UnOp::BitRev,
544                _ => return None,
545            })
546        };
547        let bin = |n: &str| {
548            Some(match n {
549                "udiv" => BinOp::UDiv,
550                "urem" => BinOp::URem,
551                "sdiv" => BinOp::SDiv,
552                "srem" => BinOp::SRem,
553                "rotl" => BinOp::RotL,
554                "rotr" => BinOp::RotR,
555                "umulhi" => BinOp::UMulHi,
556                "smulhi" => BinOp::SMulHi,
557                "pdep" => BinOp::Pdep,
558                "pext" => BinOp::Pext,
559                _ => return None,
560            })
561        };
562        let derived = |n: &str| {
563            Some(match n {
564                "umin" => Derived::UMin,
565                "umax" => Derived::UMax,
566                "smin" => Derived::SMin,
567                "smax" => Derived::SMax,
568                "andn" => Derived::AndN,
569                "orn" => Derived::OrN,
570                "xnor" => Derived::XNor,
571                "abs" => Derived::Abs,
572                "add_carry" => Derived::AddCarry,
573                "sub_borrow" => Derived::SubBorrow,
574                "sadd_overflow" => Derived::SAddOverflow,
575                "ssub_overflow" => Derived::SSubOverflow,
576                "add_sat_u" => Derived::AddSatU,
577                "add_sat_s" => Derived::AddSatS,
578                "sub_sat_u" => Derived::SubSatU,
579                "sub_sat_s" => Derived::SubSatS,
580                _ => return None,
581            })
582        };
583        let span = |p: &Self| (start.0, p.toks[p.pos.saturating_sub(1)].end);
584        let n = if let Some(op) = un(name) {
585            let a = self.args(1)?[0];
586            let sp = span(self);
587            let n = self.node(Kind::Un(op, a), sp);
588            self.unify(n, a, sp)?;
589            n
590        } else if let Some(op) = bin(name) {
591            let a = self.args(2)?;
592            let sp = span(self);
593            self.unify(a[0], a[1], sp)?;
594            let n = self.node(Kind::Bin(op, a[0], a[1]), sp);
595            self.unify(n, a[0], sp)?;
596            n
597        } else if let Some(d) = derived(name) {
598            let unary = d == Derived::Abs;
599            let a = self.args(if unary { 1 } else { 2 })?;
600            let (x, y) = (a[0], if unary { a[0] } else { a[1] });
601            let sp = span(self);
602            self.unify(x, y, sp)?;
603            let n = self.node(Kind::Derived(d, x, y), sp);
604            if matches!(
605                d,
606                Derived::AddCarry
607                    | Derived::SubBorrow
608                    | Derived::SAddOverflow
609                    | Derived::SSubOverflow
610            ) {
611                self.fix(n, 1, sp)?;
612            } else {
613                self.unify(n, x, sp)?;
614            }
615            n
616        } else {
617            match name {
618                "zext" | "sext" | "trunc" => {
619                    let g = self.generics(1)?;
620                    let a = self.args(1)?[0];
621                    let sp = span(self);
622                    let to = g[0];
623                    if Width::new(to).is_err() {
624                        return Err(SyntaxError::new("width must be in 1..=512", sp.0, sp.1));
625                    }
626                    let kind = match name {
627                        "zext" => Kind::Zext(a),
628                        "sext" => Kind::Sext(a),
629                        _ => Kind::Extract(0, a),
630                    };
631                    let n = self.node(kind, sp);
632                    self.fix(n, to, sp)?;
633                    n
634                }
635                "extract" => {
636                    let g = self.generics(2)?;
637                    let a = self.args(1)?[0];
638                    let sp = span(self);
639                    if Width::new(g[1]).is_err() {
640                        return Err(SyntaxError::new("width must be in 1..=512", sp.0, sp.1));
641                    }
642                    let n = self.node(Kind::Extract(g[0], a), sp);
643                    self.fix(n, g[1], sp)?;
644                    n
645                }
646                "concat" => {
647                    let a = self.args(2)?;
648                    let sp = span(self);
649                    self.node(Kind::Concat(a[0], a[1]), sp)
650                }
651                "select" => {
652                    let a = self.args(3)?;
653                    let sp = span(self);
654                    self.fix(a[0], 1, sp)?;
655                    self.unify(a[1], a[2], sp)?;
656                    let n = self.node(Kind::Select(a[0], a[1], a[2]), sp);
657                    self.unify(n, a[1], sp)?;
658                    n
659                }
660                _ => return self.error("unknown function"),
661            }
662        };
663        self.depth -= 1;
664        Ok(n)
665    }
666}
667
668/// Parses digits into little-endian limbs (at most 512 bits).
669fn parse_limbs(digits: &str, radix: u32) -> Option<Vec<u64>> {
670    let mut acc = vec![0u64; 9];
671    for ch in digits.chars() {
672        let d = ch.to_digit(radix)?;
673        let mut carry = u128::from(d);
674        for x in acc.iter_mut() {
675            let t = u128::from(*x) * u128::from(radix) + carry;
676            *x = t as u64;
677            carry = t >> 64;
678        }
679        if carry != 0 || acc[8] != 0 {
680            return None;
681        }
682    }
683    acc.truncate(8);
684    Some(acc)
685}
686
687/// One pass of concatenation-width propagation in the given node order; returns whether
688/// anything changed.
689fn concat_pass(p: &mut Parser<'_>, order: &[usize]) -> PResult<bool> {
690    let mut changed = false;
691    for &i in order {
692        if matches!(p.nodes[i].kind, Kind::Ext(..)) {
693            changed |= ext_pass(p, i)?;
694            continue;
695        }
696        let Kind::Concat(h, l) = p.nodes[i].kind else {
697            continue;
698        };
699        let (vn, vh, vl) = (p.nodes[i].var, p.nodes[h].var, p.nodes[l].var);
700        let (wn, wh, wl) = (p.widths.get(vn), p.widths.get(vh), p.widths.get(vl));
701        let span = p.nodes[i].span;
702        let bad = || SyntaxError::new("concatenation widths do not fit", span.0, span.1);
703        match (wn, wh, wl) {
704            (None, Some(a), Some(b)) => {
705                let t = u32::from(a) + u32::from(b);
706                if t > u32::from(Width::MAX_BITS) {
707                    return Err(bad());
708                }
709                p.widths.fix(vn, t as u16);
710                changed = true;
711            }
712            (Some(t), Some(a), None) => {
713                if t <= a {
714                    return Err(bad());
715                }
716                p.widths.fix(vl, t - a);
717                changed = true;
718            }
719            (Some(t), None, Some(b)) => {
720                if t <= b {
721                    return Err(bad());
722                }
723                p.widths.fix(vh, t - b);
724                changed = true;
725            }
726            (Some(t), Some(a), Some(b)) if u32::from(t) != u32::from(a) + u32::from(b) => {
727                return Err(bad());
728            }
729            _ => {}
730        }
731    }
732    Ok(changed)
733}
734
735/// Propagates concatenation widths bottom-up and top-down until nothing changes.
736fn concat_fixpoint(p: &mut Parser<'_>) -> PResult<()> {
737    let concats: Vec<usize> = (0..p.nodes.len())
738        .filter(|&i| matches!(p.nodes[i].kind, Kind::Concat(..) | Kind::Ext(..)))
739        .collect();
740    if concats.is_empty() {
741        return Ok(());
742    }
743    let rev: Vec<usize> = concats.iter().rev().copied().collect();
744    loop {
745        let up = concat_pass(p, &concats)?;
746        let down = concat_pass(p, &rev)?;
747        if !up && !down {
748            return Ok(());
749        }
750    }
751}
752
753/// The operand nodes of a parsed node.
754fn operands(k: &Kind) -> Vec<usize> {
755    match k {
756        Kind::Lit(_) | Kind::NegLit(_) | Kind::Bool(_) | Kind::Sym(_) => Vec::new(),
757        Kind::Un(_, a) | Kind::Zext(a) | Kind::Sext(a) | Kind::Extract(_, a) => vec![*a],
758        Kind::Bin(_, a, b) | Kind::Cmp(_, a, b) | Kind::Concat(a, b) | Kind::Derived(_, a, b) => {
759            vec![*a, *b]
760        }
761        Kind::Select(a, b, c) => vec![*a, *b, *c],
762        Kind::Ext(_, _, args) => args.clone(),
763    }
764}
765
766/// An extension call's output width from its arguments' widths (once they are all known).
767fn ext_pass(p: &mut Parser<'_>, i: usize) -> PResult<bool> {
768    let Kind::Ext(op, k, args) = &p.nodes[i].kind else {
769        return Ok(false);
770    };
771    let span = p.nodes[i].span;
772    let err = |m: String| SyntaxError::new(&m, span.0, span.1);
773    let mut widths = Vec::with_capacity(args.len());
774    for &a in args {
775        match p.widths.get(p.nodes[a].var) {
776            Some(w) => widths.push(Width::new(w).map_err(|e| err(e.to_string()))?),
777            None => return Ok(false),
778        }
779    }
780    let o =
781        p.cx.registry()
782            .and_then(|r| r.op(*op))
783            .ok_or_else(|| err("no such extension operation".into()))?;
784    let sig = o
785        .signature(&widths)
786        .map_err(|why| err(format!("`{}`: {why}", o.name())))?;
787    if sig.is_empty() || sig.len() > crate::ext::MAX_OUTPUTS {
788        return Err(err(format!(
789            "`{}` declares {} outputs (1 to {})",
790            o.name(),
791            sig.len(),
792            crate::ext::MAX_OUTPUTS
793        )));
794    }
795    let w = sig
796        .width(usize::from(*k))
797        .ok_or_else(|| err(format!("`{}` has no output {k}", o.name())))?;
798    let v = p.nodes[i].var;
799    match p.widths.get(v) {
800        None => {
801            p.widths.fix(v, w.bits());
802            Ok(true)
803        }
804        Some(have) if have != w.bits() => Err(err(format!(
805            "`{}` output {k} has {} bits, not {have}",
806            o.name(),
807            w.bits()
808        ))),
809        Some(_) => Ok(false),
810    }
811}
812
813/// Resolves every width: concatenations, then the default for every still-unknown leaf at
814/// once, then concatenations again. Linear in the input apart from the (rare) alternation
815/// between nested concatenations.
816fn resolve(p: &mut Parser<'_>) -> PResult<Vec<u16>> {
817    concat_fixpoint(p)?;
818    // Leaves take the default width in stages: first those below an extension call's arguments
819    // (a call's output width follows from them), then the other symbols, then literals, with the
820    // widths propagated after each stage. So a leaf next to a call's output takes that output's
821    // width, not the default.
822    let mut under_ext = vec![false; p.nodes.len()];
823    for i in (0..p.nodes.len()).rev() {
824        if let Kind::Ext(_, _, args) = &p.nodes[i].kind {
825            let mut stack = args.clone();
826            while let Some(j) = stack.pop() {
827                if under_ext[j] {
828                    continue;
829                }
830                under_ext[j] = true;
831                stack.extend(operands(&p.nodes[j].kind));
832            }
833        }
834    }
835    for stage in 0..3 {
836        let mut defaulted = false;
837        for (i, &under) in under_ext.iter().enumerate() {
838            let is_leaf = matches!(
839                p.nodes[i].kind,
840                Kind::Sym(_) | Kind::Lit(_) | Kind::NegLit(_)
841            );
842            let leaf = is_leaf
843                && match stage {
844                    0 => under,
845                    1 => matches!(p.nodes[i].kind, Kind::Sym(_)),
846                    _ => true,
847                };
848            let v = p.nodes[i].var;
849            if leaf && p.widths.get(v).is_none() {
850                match p.opts.default_width {
851                    Some(w) => {
852                        p.widths.fix(v, w.bits());
853                        defaulted = true;
854                    }
855                    None => {
856                        let span = p.nodes[i].span;
857                        return Err(SyntaxError::new(
858                            "cannot infer this width; write `:W` (for example `1:32`)",
859                            span.0,
860                            span.1,
861                        ));
862                    }
863                }
864            }
865        }
866        if defaulted {
867            concat_fixpoint(p)?;
868        }
869    }
870    let mut out = Vec::with_capacity(p.nodes.len());
871    for i in 0..p.nodes.len() {
872        let v = p.nodes[i].var;
873        match p.widths.get(v) {
874            Some(w) => out.push(w),
875            None => {
876                let span = p.nodes[i].span;
877                return Err(SyntaxError::new("cannot infer this width", span.0, span.1));
878            }
879        }
880    }
881    validate(&p.nodes, &out)?;
882    Ok(out)
883}
884
885/// Checks everything the builder would reject, before any node or symbol is created, so a
886/// failed parse leaves the context unchanged.
887fn validate(nodes: &[PNode], widths: &[u16]) -> PResult<()> {
888    for (i, n) in nodes.iter().enumerate() {
889        let w = widths[i];
890        let err = |m: &str| Err(SyntaxError::new(m, n.span.0, n.span.1));
891        match &n.kind {
892            Kind::Lit(limbs) => {
893                let width =
894                    Width::new(w).map_err(|_| SyntaxError::new("bad width", n.span.0, n.span.1))?;
895                if BitVec::from_limbs(width, limbs).is_err() {
896                    return err(&format!("literal does not fit in {w} bits"));
897                }
898            }
899            Kind::NegLit(limbs) => {
900                let width =
901                    Width::new(w).map_err(|_| SyntaxError::new("bad width", n.span.0, n.span.1))?;
902                let fits = BitVec::from_limbs(width, limbs)
903                    .is_ok_and(|m| m.is_zero() || m == BitVec::smin(width) || !m.msb());
904                if !fits {
905                    return err(&format!(
906                        "negative literal does not fit in {w} bits (signed)"
907                    ));
908                }
909            }
910            Kind::Un(UnOp::Bswap, _) if !w.is_multiple_of(8) => {
911                return err("bswap needs a width that is a multiple of 8");
912            }
913            Kind::Zext(a) | Kind::Sext(a) if widths[*a] > w => {
914                return err(&format!("cannot extend {} bits to {w} bits", widths[*a]));
915            }
916            Kind::Extract(lo, a) if u32::from(*lo) + u32::from(w) > u32::from(widths[*a]) => {
917                return err(&format!(
918                    "extract of bits [{lo}, {lo}+{w}) does not fit in {} bits",
919                    widths[*a]
920                ));
921            }
922            _ => {}
923        }
924    }
925    Ok(())
926}
927
928impl Context {
929    /// Parses an expression in the text syntax (see `docs/design.md` ยง7.1), creating symbols
930    /// as needed, and builds it through the canonicalizing constructors.
931    ///
932    /// ```
933    /// use bitwright::{Context, ParseOptions, Width};
934    /// let mut cx = Context::new();
935    /// let e = cx.parse("(y | x) + (y & x)", &ParseOptions::width(Width::W64))?;
936    /// // Built canonically: operands of commutative operators in one order.
937    /// assert_eq!(cx.display(e).to_string(), "(x & y) + (x | y)");
938    /// # Ok::<(), bitwright::Error>(())
939    /// ```
940    pub fn parse(&mut self, src: &str, opts: &ParseOptions) -> Result<Expr, Error> {
941        let toks = lex(src).map_err(Error::Syntax)?;
942        let (nodes, widths, root) = {
943            let mut p = Parser {
944                toks,
945                pos: 0,
946                nodes: Vec::new(),
947                widths: Widths {
948                    parent: Vec::new(),
949                    value: Vec::new(),
950                },
951                lets: HashMap::new(),
952                sym_vars: HashMap::new(),
953                cx: self,
954                opts,
955                depth: 0,
956            };
957            let root = p.top().map_err(Error::Syntax)?;
958            let widths = resolve(&mut p).map_err(Error::Syntax)?;
959            (p.nodes, widths, root)
960        };
961        let mut built: Vec<Expr> = Vec::with_capacity(nodes.len());
962        for (i, n) in nodes.iter().enumerate() {
963            let w = Width::new(widths[i]).map_err(Error::Width)?;
964            let at = |j: usize| built[j];
965            let spanned = |e: Error| match e {
966                Error::Width(we) => {
967                    Error::Syntax(SyntaxError::new(&we.to_string(), n.span.0, n.span.1))
968                }
969                Error::Value(_) => Error::Syntax(SyntaxError::new(
970                    &format!("literal does not fit in {} bits", w.bits()),
971                    n.span.0,
972                    n.span.1,
973                )),
974                other => other,
975            };
976            let e = match &n.kind {
977                Kind::Lit(limbs) => BitVec::from_limbs(w, limbs)
978                    .map_err(Error::Value)
979                    .and_then(|v| self.constant(&v)),
980                Kind::NegLit(limbs) => BitVec::from_limbs(w, limbs)
981                    .map_err(Error::Value)
982                    .and_then(|v| self.constant(&BitVec::un_unchecked(UnOp::Neg, &v))),
983                Kind::Bool(b) => self.bool(*b),
984                Kind::Sym(key) => self.symbol(key.clone(), w),
985                Kind::Un(op, a) => self.un(*op, at(*a)),
986                Kind::Bin(op, a, b) => self.bin(*op, at(*a), at(*b)),
987                Kind::Cmp(op, a, b) => self.cmp(*op, at(*a), at(*b)),
988                Kind::Zext(a) => self.zext(at(*a), w),
989                Kind::Sext(a) => self.sext(at(*a), w),
990                Kind::Extract(lo, a) => self.extract(at(*a), *lo, w),
991                Kind::Concat(h, l) => self.concat(at(*h), at(*l)),
992                Kind::Select(c, t, f) => self.select(at(*c), at(*t), at(*f)),
993                Kind::Ext(op, k, args) => {
994                    let args: Vec<Expr> = args.iter().map(|&a| at(a)).collect();
995                    self.ext_output(*op, usize::from(*k), &args)
996                }
997                Kind::Derived(d, a, b) => {
998                    let (a, b) = (at(*a), at(*b));
999                    match d {
1000                        Derived::UMin => self.umin(a, b),
1001                        Derived::UMax => self.umax(a, b),
1002                        Derived::SMin => self.smin(a, b),
1003                        Derived::SMax => self.smax(a, b),
1004                        Derived::AndN => self.andn(a, b),
1005                        Derived::OrN => self.orn(a, b),
1006                        Derived::XNor => self.xnor(a, b),
1007                        Derived::Abs => self.abs(a),
1008                        Derived::AddCarry => self.add_carry(a, b),
1009                        Derived::SubBorrow => self.sub_borrow(a, b),
1010                        Derived::SAddOverflow => self.sadd_overflow(a, b),
1011                        Derived::SSubOverflow => self.ssub_overflow(a, b),
1012                        Derived::AddSatU => self.add_sat_u(a, b),
1013                        Derived::AddSatS => self.add_sat_s(a, b),
1014                        Derived::SubSatU => self.sub_sat_u(a, b),
1015                        Derived::SubSatS => self.sub_sat_s(a, b),
1016                    }
1017                }
1018            }
1019            .map_err(spanned)?;
1020            built.push(e);
1021        }
1022        Ok(built[root])
1023    }
1024}