xq_lang/
ast.rs

1use std::fmt::{Display, Formatter};
2
3use derive_more::From;
4
5use crate::Number;
6
7#[derive(Debug, Clone, Eq, PartialEq, Hash)]
8pub struct Identifier(pub String);
9
10impl Display for Identifier {
11    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
12        f.write_str(&self.0)
13    }
14}
15
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17pub enum UnaryOp {
18    Plus,
19    Minus,
20}
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub enum BinaryArithmeticOp {
24    Add,
25    Subtract,
26    Multiply,
27    Divide,
28    Modulo,
29}
30
31#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub enum BinaryOp {
33    Arithmetic(BinaryArithmeticOp),
34    Alt,
35    And,
36    Or,
37}
38
39#[derive(Debug, Copy, Clone, Eq, PartialEq)]
40pub enum UpdateOp {
41    Arithmetic(BinaryArithmeticOp),
42    Alt,
43    Modify,
44    Assign,
45}
46
47#[derive(Debug, Copy, Clone, Eq, PartialEq)]
48pub enum Comparator {
49    Eq,
50    Neq,
51    Gt,
52    Ge,
53    Lt,
54    Le,
55}
56
57#[derive(Debug, Clone, Eq, PartialEq)]
58pub enum Suffix {
59    /// `'?'`
60    Optional,
61    /// `'[' ']'`
62    Iterate,
63    /// `'.' <ident>`
64    Index(Identifier),
65    /// `'[' query ']' | '.' <string>`
66    Query(Box<Query>),
67    /// `'[' (<query>)? ':' (<query>)? ']' except '[' ':' ']'`
68    Slice(Option<Box<Query>>, Option<Box<Query>>),
69}
70
71#[derive(Debug, Clone, Eq, PartialEq)]
72pub enum StringFragment {
73    String(String),
74    Query(Query),
75}
76
77#[derive(Debug, Clone, Eq, PartialEq)]
78pub enum ObjectBindPatternEntry {
79    /// `<variable>`
80    KeyOnly(Identifier),
81    /// `(<ident> | <keyword> | <string> | '(' <query> ')') ':' pattern`
82    ValueOnly(Box<Query>, Box<BindPattern>),
83    /// `<variable> ':' pattern`
84    KeyAndValue(Identifier, Box<BindPattern>),
85}
86
87#[derive(Debug, Clone, Eq, PartialEq)]
88pub enum BindPattern {
89    /// `<variable>`
90    Variable(Identifier),
91    /// `'[' <patten> (',' <pattern>)* ']'`
92    Array(Vec<BindPattern>),
93    /// `'{' <object pattern elem> (',' <object pattern elem>)* '}'`
94    Object(Vec<ObjectBindPatternEntry>),
95}
96
97#[derive(Debug, Clone, Eq, PartialEq)]
98pub enum FuncArg {
99    Variable(Identifier),
100    Closure(Identifier),
101}
102
103#[derive(Debug, Clone, Eq, PartialEq)]
104pub struct FuncDef {
105    pub name: Identifier,
106    pub args: Vec<FuncArg>,
107    pub body: Box<Query>,
108}
109
110#[derive(Debug, Clone, Eq, PartialEq)]
111pub enum Term {
112    /// `'null' | 'true' | 'false' | <number>`
113    Constant(ConstantPrimitive),
114    /// `<string>`
115    String(Vec<StringFragment>),
116
117    /// `'.'`
118    Identity,
119    /// `'..'`
120    Recurse,
121    /// ```text
122    /// '.' '[' ( | <query> | (<query>)? ':' (<query>)? ) ']'
123    /// '.' (<ident> | <string>)
124    /// <term> '[' ( | <query> | (<query>)? ':' (<query>)? ) ']'
125    /// <term> '.' '[' ( | <query> | (<query>)? ':' (<query>)? ) ']'
126    /// <term> '?'
127    /// <term> '.' (<ident> | <string>)
128    /// ```
129    Suffix(Box<Term>, Suffix),
130
131    /// `(<var> | <modulevar>)`
132    Variable(Identifier),
133    /// `(<ident> | <moduleident>) ( '(' query (';' query)* ')' )? | (<var> | <modulevar>)`
134    FunctionCall { name: Identifier, args: Vec<Query> },
135    /// `'@' <ident-allowing-num-prefix> (<string>)?`
136    Format(Identifier, Option<Vec<StringFragment>>),
137    /// `'(' <query> ')'`
138    Query(Box<Query>),
139    /// `('+' | '-') <term>`
140    Unary(UnaryOp, Box<Term>),
141    /// `'{' (<ident> | <variable> | <keyword> | <string> | '(' <query> ')') (':' <term> ('|' <term>)*)? (',' ....)* ','? '}'`
142    Object(Vec<(Query, Option<Query>)>),
143    /// `'[' (<query>)? ']'`
144    Array(Option<Box<Query>>),
145    /// `'break' <variable>`
146    Break(Identifier),
147}
148
149#[derive(Debug, Clone, Eq, PartialEq)]
150pub enum Query {
151    /// `<term> | <query> '?'`
152    Term(Box<Term>),
153    /// `'def' <ident> ( '(' <ident> | <var> (';' <ident> | <var>)* ')' )? ':' <query> ';' <query>`
154    WithFunc {
155        function: FuncDef,
156        query: Box<Query>,
157    },
158    /// `<query> ('|' <query>)+`
159    Pipe { lhs: Box<Query>, rhs: Box<Query> },
160    /// `<query> (',' <query>)+`
161    Concat { lhs: Box<Query>, rhs: Box<Query> },
162    /// `<term> 'as' <pattern> ('?//' <pattern>)* '|' <query>`
163    Bind {
164        source: Box<Term>,
165        patterns: Vec<BindPattern>,
166        body: Box<Query>,
167    },
168    /// `'reduce' <term> 'as' <pattern> '(' <query> ';' <query> ')'`
169    Reduce {
170        source: Box<Term>,
171        pattern: BindPattern,
172        initial: Box<Query>,
173        accumulator: Box<Query>,
174    },
175    /// `'foreach' <term> 'as' <pattern> '(' <query> ';' <query> (';' <query>)? ')'`
176    ForEach {
177        source: Box<Term>,
178        pattern: BindPattern,
179        initial: Box<Query>,
180        update: Box<Query>,
181        extract: Option<Box<Query>>,
182    },
183    /// `'if' <query> 'then' <query> ('elif' <query> 'then' <query>)* ('else' <query>)? 'end'`
184    If {
185        cond: Box<Query>,
186        positive: Box<Query>,
187        negative: Option<Box<Query>>,
188    },
189    /// `'try' <query> ('catch' <query>)?`
190    Try {
191        body: Box<Query>,
192        catch: Option<Box<Query>>,
193    },
194    /// `'label' <variable> '|' <query>`
195    Label { label: Identifier, body: Box<Query> },
196
197    /// `<query> ('//' | '+' | '-' | '*' | '/' | '%' | 'and' | 'or') <query>`
198    Operate {
199        lhs: Box<Query>,
200        operator: BinaryOp,
201        rhs: Box<Query>,
202    },
203    /// `<query> ('=' | '|=' | '//=' | '+=' | '-=' | '*=' | '/=' | '%=') <query>`
204    Update {
205        lhs: Box<Query>,
206        operator: UpdateOp,
207        rhs: Box<Query>,
208    },
209    /// `<query> <comparator> <query>`
210    Compare {
211        lhs: Box<Query>,
212        comparator: Comparator,
213        rhs: Box<Query>,
214    },
215}
216
217#[derive(Debug, Clone, Eq, PartialEq)]
218pub enum ConstantPrimitive {
219    Null,
220    False,
221    True,
222    Number(Number),
223    String(String),
224}
225
226#[derive(Debug, Clone, Eq, PartialEq, From)]
227pub enum ConstantValue {
228    Primitive(ConstantPrimitive),
229    Array(ConstantArray),
230    Object(ConstantObject),
231}
232
233#[derive(Debug, Clone, Eq, PartialEq, Default)]
234pub struct ConstantArray(pub Vec<ConstantValue>);
235
236#[derive(Debug, Clone, Eq, PartialEq, Default)]
237pub struct ConstantObject(pub Vec<(String, ConstantValue)>);
238
239#[derive(Debug, Clone, Eq, PartialEq)]
240pub struct Import {
241    pub path: String,
242    pub alias: Option<Identifier>,
243    pub meta: Option<ConstantObject>,
244}
245
246#[derive(Debug, Clone, Eq, PartialEq)]
247pub struct Program {
248    pub module_header: Option<ConstantObject>,
249    pub imports: Vec<Import>,
250    pub functions: Vec<FuncDef>,
251    pub query: Query,
252}
253
254impl From<&str> for Identifier {
255    fn from(s: &str) -> Self {
256        Self(s.to_string())
257    }
258}
259
260impl From<Term> for Query {
261    fn from(term: Term) -> Self {
262        if let Term::Query(query) = term {
263            *query
264        } else {
265            Query::Term(Box::new(term))
266        }
267    }
268}
269
270impl From<Query> for Term {
271    fn from(query: Query) -> Self {
272        if let Query::Term(term) = query {
273            *term
274        } else {
275            Term::Query(Box::new(query))
276        }
277    }
278}