Skip to main content

truecalc_core/parser/
ast.rs

1use super::refs::Ref;
2use crate::types::ErrorKind;
3
4/// Byte range of a node within the original formula string.
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct Span {
7    pub offset: usize, // byte offset from start of formula
8    pub length: usize,
9}
10
11impl Span {
12    pub fn new(offset: usize, length: usize) -> Self {
13        Self { offset, length }
14    }
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub enum UnaryOp {
19    Neg,     // -x
20    Percent, // x% → x/100
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub enum BinaryOp {
25    Add, Sub, Mul, Div, Pow,
26    Concat,         // &
27    Eq, Ne, Lt, Gt, Le, Ge,
28}
29
30#[derive(Debug, Clone, PartialEq)]
31pub enum Expr {
32    Number(f64, Span),
33    Text(String, Span),
34    Bool(bool, Span),
35    /// An error literal typed directly into a formula (`=#REF!`,
36    /// `=#REF!+1`) — parses straight to its error value, the same way
37    /// `Number`/`Text`/`Bool` parse straight to theirs. Distinct from an
38    /// error *produced* by evaluation (e.g. `=1/0`), which never round-trips
39    /// through this variant.
40    Error(ErrorKind, Span),
41    Variable(String, Span),
42    /// Sheet-qualified reference: `Sheet1!A1`, `'Q2 Data'!A1:B2`.
43    /// Bare cell/range references (`A1`, `A1:D4`) and bare names remain
44    /// [`Expr::Variable`]; sheet-qualified forms always carry `sheet: Some(_)`.
45    Reference(Ref, Span),
46    UnaryOp {
47        op: UnaryOp,
48        operand: Box<Expr>,
49        span: Span,
50    },
51    BinaryOp {
52        op: BinaryOp,
53        left: Box<Expr>,
54        right: Box<Expr>,
55        span: Span,
56    },
57    FunctionCall {
58        name: String,   // always uppercased
59        args: Vec<Expr>,
60        span: Span,
61    },
62    Array(Vec<Expr>, Span),
63    /// Immediately-invoked function application: `expr(call_args)`.
64    /// Used for LAMBDA: `LAMBDA(x, x*2)(5)` → `Apply { func: LAMBDA(...), call_args: [5] }`.
65    Apply {
66        func: Box<Expr>,
67        call_args: Vec<Expr>,
68        span: Span,
69    },
70}
71
72impl Expr {
73    pub fn span(&self) -> &Span {
74        match self {
75            Expr::Number(_, s) | Expr::Text(_, s) | Expr::Bool(_, s) | Expr::Error(_, s) | Expr::Variable(_, s) | Expr::Reference(_, s) => s,
76            Expr::UnaryOp { span, .. }
77            | Expr::BinaryOp { span, .. }
78            | Expr::FunctionCall { span, .. }
79            | Expr::Apply { span, .. } => span,
80            Expr::Array(_, span) => span,
81        }
82    }
83}
84
85#[cfg(test)]
86mod tests;