scout_parser/
ast.rs

1use std::{collections::HashMap, fmt::Display};
2
3use scout_lexer::Token;
4
5#[derive(Debug)]
6pub enum NodeKind {
7    Program(Program),
8    Stmt(StmtKind),
9    Expr(ExprKind),
10}
11
12#[derive(Debug, Default)]
13pub struct Program {
14    pub stmts: Vec<StmtKind>,
15}
16
17#[derive(Debug, PartialEq, Clone)]
18pub enum StmtKind {
19    Assign(ExprKind, ExprKind),
20    Crawl(CrawlLiteral),
21    Expr(ExprKind),
22    ForLoop(ForLoop),
23    WhileLoop(ExprKind, Block),
24    Func(FuncDef),
25    Goto(ExprKind),
26    IfElse(IfElseLiteral),
27    Return(Option<ExprKind>),
28    Scrape(HashLiteral),
29    Screenshot(String),
30    TryCatch(Block, Option<Block>),
31    Use(ExprKind),
32}
33
34#[derive(Debug, PartialEq, Clone)]
35pub enum ExprKind {
36    // Literals
37    Str(String),
38    Number(f64),
39    Boolean(bool),
40    Ident(Identifier),
41    List(Vec<ExprKind>),
42    Map(HashLiteral),
43    Null,
44
45    // Selects
46    Select(String, Option<Identifier>),
47    SelectAll(String, Option<Identifier>),
48
49    // Rest
50    Call(CallLiteral),
51    Chain(Vec<ExprKind>),
52    Infix(Box<ExprKind>, Token, Box<ExprKind>),
53    Prefix(Box<ExprKind>, Token),
54}
55
56#[derive(Debug, PartialEq, Clone)]
57pub struct CallLiteral {
58    pub ident: Identifier,
59    pub args: Vec<ExprKind>,
60    pub kwargs: Vec<Kwarg>,
61}
62
63#[derive(Debug, PartialEq, Clone)]
64pub struct Kwarg {
65    pub ident: Identifier,
66    pub expr: ExprKind,
67}
68
69#[derive(Debug, PartialEq, Clone)]
70pub struct CrawlLiteral {
71    pub bindings: Option<CrawlBindings>,
72    pub filter: Option<ExprKind>,
73    pub body: Block,
74}
75
76#[derive(Debug, PartialEq, Clone)]
77pub struct CrawlBindings {
78    pub link: Identifier,
79    pub depth: Identifier,
80}
81
82impl CrawlLiteral {
83    pub fn new(bindings: Option<CrawlBindings>, filter: Option<ExprKind>, body: Block) -> Self {
84        Self {
85            bindings,
86            filter,
87            body,
88        }
89    }
90}
91
92#[derive(Debug, PartialEq, Eq, Hash, Clone)]
93pub struct Identifier {
94    pub name: String,
95}
96
97impl Identifier {
98    pub fn new(name: String) -> Self {
99        Self { name }
100    }
101}
102
103#[derive(Debug, PartialEq, Clone)]
104pub struct IfElseLiteral {
105    pub if_lit: IfLiteral,
106    pub elifs: Vec<IfLiteral>,
107    pub else_lit: Option<ElseLiteral>,
108}
109
110#[derive(Debug, PartialEq, Clone)]
111pub struct IfLiteral {
112    pub cond: ExprKind,
113    pub block: Block,
114}
115
116#[derive(Debug, PartialEq, Clone)]
117pub struct ElseLiteral {
118    pub block: Block,
119}
120
121#[derive(Debug, PartialEq, Clone)]
122pub struct FuncDef {
123    pub ident: Identifier,
124    pub params: Vec<FnParam>,
125    pub body: Block,
126}
127
128impl FuncDef {
129    pub fn new(ident: Identifier, params: Vec<FnParam>, body: Block) -> Self {
130        Self {
131            ident,
132            params,
133            body,
134        }
135    }
136}
137
138#[derive(Debug, PartialEq, Clone)]
139pub struct FnParam {
140    pub ident: Identifier,
141    pub default: Option<ExprKind>,
142}
143
144impl FnParam {
145    pub fn new(ident: Identifier, default: Option<ExprKind>) -> Self {
146        Self { ident, default }
147    }
148}
149
150#[derive(Default, Debug, PartialEq, Eq, Clone)]
151pub struct SelectLiteral {
152    pub selector: String,
153}
154
155impl SelectLiteral {
156    pub fn new(selector: String) -> Self {
157        Self { selector }
158    }
159}
160
161#[derive(Default, Debug, PartialEq, Clone)]
162pub struct HashLiteral {
163    pub pairs: HashMap<Identifier, ExprKind>,
164}
165
166impl From<Vec<(Identifier, ExprKind)>> for HashLiteral {
167    fn from(value: Vec<(Identifier, ExprKind)>) -> Self {
168        let pairs = HashMap::from_iter(value.iter().map(|(i, s)| (i.clone(), s.clone())));
169        Self { pairs }
170    }
171}
172
173impl Display for Identifier {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        write!(f, "{}", self.name)
176    }
177}
178
179#[derive(Debug, PartialEq, Clone)]
180pub struct ForLoop {
181    pub ident: Identifier,
182    pub iterable: ExprKind,
183    pub block: Block,
184}
185
186impl ForLoop {
187    pub fn new(ident: Identifier, iterable: ExprKind, block: Block) -> Self {
188        Self {
189            ident,
190            iterable,
191            block,
192        }
193    }
194}
195
196#[derive(Debug, PartialEq, Clone, Default)]
197pub struct Block {
198    pub stmts: Vec<StmtKind>,
199}
200
201impl Block {
202    pub fn new(stmts: Vec<StmtKind>) -> Self {
203        Self { stmts }
204    }
205}
206
207impl std::fmt::Display for FnParam {
208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        write!(f, "{}", self.ident)?;
210        if let Some(default) = &self.default {
211            write!(f, " = {default}")?;
212        }
213
214        Ok(())
215    }
216}
217
218impl std::fmt::Display for FuncDef {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        let mut param_str = String::new();
221        for (idx, param) in self.params.iter().enumerate() {
222            param_str.push_str(param.to_string().as_str());
223            if idx != self.params.len() - 1 {
224                param_str.push_str(", ");
225            }
226        }
227        writeln!(f, "def {}({param_str}) do\n{}\nend", self.ident, self.body)
228    }
229}
230
231impl std::fmt::Display for CallLiteral {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        write!(f, "{}(", self.ident)?;
234        for (idx, arg) in self.args.iter().enumerate() {
235            write!(f, "{arg}")?;
236            if idx != self.args.len() - 1 {
237                write!(f, ", ")?;
238            }
239        }
240
241        if !self.kwargs.is_empty() {
242            write!(f, ", ")?;
243
244            for (idx, kwarg) in self.kwargs.iter().enumerate() {
245                write!(f, "{kwarg}")?;
246                if idx != self.kwargs.len() - 1 {
247                    write!(f, ", ")?;
248                }
249            }
250        }
251
252        write!(f, ")")
253    }
254}
255
256impl std::fmt::Display for Kwarg {
257    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258        write!(f, "{} = {}", self.ident, self.expr)
259    }
260}
261
262impl std::fmt::Display for HashLiteral {
263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264        write!(f, "{{ ")?;
265        for (idx, (i, o)) in self.pairs.iter().enumerate() {
266            write!(f, "{}: {}", i, o)?;
267            if idx != self.pairs.len() - 1 {
268                write!(f, ", ")?;
269            }
270        }
271        write!(f, " }}")
272    }
273}
274
275impl std::fmt::Display for Block {
276    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277        for stmt in &self.stmts {
278            write!(f, "{stmt}\n")?;
279        }
280        Ok(())
281    }
282}
283
284impl std::fmt::Display for ExprKind {
285    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
286        use ExprKind::*;
287        match self {
288            Str(s) => write!(f, r#""{s}""#),
289            Number(n) => write!(f, "{n}"),
290            Boolean(b) => write!(f, "{b}"),
291            Ident(ident) => write!(f, "{ident}"),
292            List(l) => {
293                write!(f, "[")?;
294                for (i, obj) in l.iter().enumerate() {
295                    write!(f, "{obj}")?;
296                    if i != l.len() - 1 {
297                        write!(f, ", ")?;
298                    }
299                }
300
301                write!(f, "]")
302            }
303            Map(hash) => write!(f, "{hash}"),
304            Null => write!(f, "null"),
305            Select(s, mb_ident) => match mb_ident {
306                Some(ident) => write!(f, r#"$({ident})"{s}""#),
307                None => write!(f, r#"$"{s}""#),
308            },
309            SelectAll(s, mb_ident) => match mb_ident {
310                Some(ident) => write!(f, r#"$$({ident})"{s}""#),
311                None => write!(f, r#"$$"{s}""#),
312            },
313            Call(lit) => write!(f, "{lit}"),
314            Chain(exprs) => {
315                for (i, expr) in exprs.iter().enumerate() {
316                    write!(f, "{expr}")?;
317                    if i != exprs.len() - 1 {
318                        write!(f, " |> ")?;
319                    }
320                }
321                Ok(())
322            }
323            Infix(lhs, op, rhs) => write!(f, "{lhs} {} {rhs}", op.literal),
324            Prefix(lhs, op) => write!(f, "{lhs} {}", op.literal),
325        }
326    }
327}
328
329impl std::fmt::Display for StmtKind {
330    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331        use StmtKind::*;
332        match self {
333            Assign(lhs, rhs) => write!(f, "{lhs} = {rhs}"),
334            Crawl(lit) => {
335                write!(f, "crawl ")?;
336
337                if let Some(bindings) = &lit.bindings {
338                    write!(f, "{}, {} ", bindings.link, bindings.depth)?;
339                }
340
341                if let Some(filter) = &lit.filter {
342                    write!(f, "where {filter}")?;
343                }
344
345                write!(f, "do\n{}end\n", lit.body)
346            }
347            Expr(expr) => write!(f, "{expr}"),
348            ForLoop(floop) => {
349                write!(
350                    f,
351                    "for {} in {} do\n{}end\n",
352                    floop.ident, floop.iterable, floop.block
353                )
354            }
355            WhileLoop(cond, block) => write!(f, "while {cond} do\n{block}end\n"),
356            Func(def) => write!(f, "{def}"),
357            Goto(expr) => write!(f, "goto {expr}"),
358            IfElse(lit) => {
359                writeln!(f, "if {} do\n{}", lit.if_lit.cond, lit.if_lit.block)?;
360                for elif in &lit.elifs {
361                    writeln!(f, "elif {} do\n{}", elif.cond, elif.block)?;
362                }
363                if let Some(el) = &lit.else_lit {
364                    writeln!(f, "else\n{}", el.block)?;
365                }
366                writeln!(f, "end")
367            }
368            Return(mb_expr) => {
369                write!(f, "return")?;
370                if let Some(expr) = mb_expr {
371                    write!(f, "{expr}")?;
372                }
373                Ok(())
374            }
375            Scrape(hash) => write!(f, "scrape {hash}"),
376            Screenshot(s) => write!(f, "screenshot {s}"),
377            TryCatch(t, c) => {
378                write!(f, "try\n{t}\n")?;
379                if let Some(catch) = c {
380                    write!(f, "catch\n{catch}\n")?;
381                }
382                write!(f, "end\n")
383            }
384            Use(expr) => write!(f, "use {expr}"),
385        }
386    }
387}
388
389impl std::fmt::Display for Program {
390    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391        for stmt in &self.stmts {
392            writeln!(f, "{stmt}")?;
393        }
394        Ok(())
395    }
396}