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 Str(String),
38 Number(f64),
39 Boolean(bool),
40 Ident(Identifier),
41 List(Vec<ExprKind>),
42 Map(HashLiteral),
43 Null,
44
45 Select(String, Option<Identifier>),
47 SelectAll(String, Option<Identifier>),
48
49 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}