1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
use rust_decimal::Decimal;
use rust_decimal_macros::dec;

use crate::compiler::error::{CompilerError, CompilerResult};
use crate::compiler::{Opcode, TypeCheckKind, TypeConversionKind};
use crate::lexer::{ArithmeticOperator, ComparisonOperator, LogicalOperator, Operator};
use crate::parser::{BuiltInFunction, Node};
use crate::variable::Variable;

#[derive(Debug)]
pub struct Compiler<'arena> {
    bytecode: Vec<Opcode<'arena>>,
}

impl<'arena> Compiler<'arena> {
    pub fn new() -> Self {
        Self {
            bytecode: Default::default(),
        }
    }

    pub fn compile(&mut self, root: &'arena Node<'arena>) -> CompilerResult<&[Opcode<'arena>]> {
        self.bytecode.clear();

        CompilerInner::new(&mut self.bytecode, root).compile()?;
        Ok(self.bytecode.as_slice())
    }
}

#[derive(Debug)]
struct CompilerInner<'arena, 'bytecode_ref> {
    root: &'arena Node<'arena>,
    bytecode: &'bytecode_ref mut Vec<Opcode<'arena>>,
}

impl<'arena, 'bytecode_ref> CompilerInner<'arena, 'bytecode_ref> {
    pub fn new(
        bytecode: &'bytecode_ref mut Vec<Opcode<'arena>>,
        root: &'arena Node<'arena>,
    ) -> Self {
        Self { root, bytecode }
    }

    pub fn compile(&mut self) -> CompilerResult<()> {
        self.compile_node(self.root)?;
        Ok(())
    }

    fn emit(&mut self, op: Opcode<'arena>) -> usize {
        self.bytecode.push(op);
        self.bytecode.len()
    }

    fn emit_loop<F>(&mut self, body: F) -> CompilerResult<()>
    where
        F: FnOnce(&mut Self) -> CompilerResult<()>,
    {
        let begin = self.bytecode.len();
        let end = self.emit(Opcode::JumpIfEnd(0));

        body(self)?;

        self.emit(Opcode::IncrementIt);
        let e = self.emit(Opcode::JumpBackward(self.calc_backward_jump(begin)));
        self.replace(end, Opcode::JumpIfEnd(e - end));
        Ok(())
    }

    fn emit_cond<F>(&mut self, mut body: F)
    where
        F: FnMut(&mut Self),
    {
        let noop = self.emit(Opcode::JumpIfFalse(0));
        self.emit(Opcode::Pop);

        body(self);

        let jmp = self.emit(Opcode::Jump(0));
        self.replace(noop, Opcode::JumpIfFalse(jmp - noop));
        let e = self.emit(Opcode::Pop);
        self.replace(jmp, Opcode::Jump(e - jmp));
    }

    fn replace(&mut self, at: usize, op: Opcode<'arena>) {
        let _ = std::mem::replace(&mut self.bytecode[at - 1], op);
    }

    fn calc_backward_jump(&self, to: usize) -> usize {
        self.bytecode.len() + 1 - to
    }

    fn compile_argument(
        &mut self,
        builtin: &BuiltInFunction,
        arguments: &[&'arena Node<'arena>],
        index: usize,
    ) -> CompilerResult<usize> {
        let arg = arguments
            .get(index)
            .ok_or_else(|| CompilerError::ArgumentNotFound {
                index,
                builtin: builtin.to_string(),
            })?;

        self.compile_node(arg)
    }

    fn compile_node(&mut self, node: &'arena Node<'arena>) -> CompilerResult<usize> {
        match node {
            Node::Null => Ok(self.emit(Opcode::Push(Variable::Null))),
            Node::Bool(v) => Ok(self.emit(Opcode::Push(Variable::Bool(*v)))),
            Node::Number(v) => Ok(self.emit(Opcode::Push(Variable::Number(*v)))),
            Node::String(v) => Ok(self.emit(Opcode::Push(Variable::String(v)))),
            Node::Pointer => Ok(self.emit(Opcode::Pointer)),
            Node::Root => Ok(self.emit(Opcode::FetchRootEnv)),
            Node::Array(v) => {
                v.iter()
                    .try_for_each(|&n| self.compile_node(n).map(|_| ()))?;
                self.emit(Opcode::Push(Variable::Number(Decimal::from(v.len()))));
                Ok(self.emit(Opcode::Array))
            }
            Node::Identifier(v) => Ok(self.emit(Opcode::FetchEnv(v))),
            Node::Closure(v) => self.compile_node(v),
            Node::Member { node, property } => {
                self.compile_node(node)?;
                self.compile_node(property)?;
                Ok(self.emit(Opcode::Fetch))
            }
            Node::TemplateString(parts) => {
                parts.iter().try_for_each(|&n| {
                    self.compile_node(n).map(|_| ())?;
                    self.emit(Opcode::TypeConversion(TypeConversionKind::String));
                    Ok(())
                })?;

                self.emit(Opcode::Push(Variable::Number(Decimal::from(parts.len()))));
                self.emit(Opcode::Array);
                self.emit(Opcode::Push(Variable::String("")));
                Ok(self.emit(Opcode::Join))
            }
            Node::Slice { node, to, from } => {
                self.compile_node(node)?;
                if let Some(t) = to {
                    self.compile_node(t)?;
                } else {
                    self.emit(Opcode::Len);
                    self.emit(Opcode::Push(Variable::Number(dec!(1))));
                    self.emit(Opcode::Subtract);
                }

                if let Some(f) = from {
                    self.compile_node(f)?;
                } else {
                    self.emit(Opcode::Push(Variable::Number(dec!(0))));
                }

                Ok(self.emit(Opcode::Slice))
            }
            Node::Interval {
                left,
                right,
                left_bracket,
                right_bracket,
            } => {
                self.compile_node(left)?;
                self.compile_node(right)?;
                Ok(self.emit(Opcode::Interval {
                    left_bracket,
                    right_bracket,
                }))
            }
            Node::Conditional {
                condition,
                on_true,
                on_false,
            } => {
                self.compile_node(condition)?;
                let otherwise = self.emit(Opcode::JumpIfFalse(0));

                self.emit(Opcode::Pop);
                self.compile_node(on_true)?;
                let end = self.emit(Opcode::Jump(0));

                self.replace(otherwise, Opcode::JumpIfFalse(end - otherwise));
                self.emit(Opcode::Pop);
                let b = self.compile_node(on_false)?;
                self.replace(end, Opcode::Jump(b - end));

                Ok(b)
            }
            Node::Unary { node, operator } => {
                let curr = self.compile_node(node)?;
                match *operator {
                    Operator::Arithmetic(ArithmeticOperator::Add) => Ok(curr),
                    Operator::Arithmetic(ArithmeticOperator::Subtract) => {
                        Ok(self.emit(Opcode::Negate))
                    }
                    Operator::Logical(LogicalOperator::Not) => Ok(self.emit(Opcode::Not)),
                    _ => Err(CompilerError::UnknownUnaryOperator {
                        operator: operator.to_string(),
                    }),
                }
            }
            Node::Binary {
                left,
                right,
                operator,
            } => match *operator {
                Operator::Comparison(ComparisonOperator::Equal) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;

                    Ok(self.emit(Opcode::Equal))
                }
                Operator::Comparison(ComparisonOperator::NotEqual) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;

                    self.emit(Opcode::Equal);
                    Ok(self.emit(Opcode::Not))
                }
                Operator::Logical(LogicalOperator::Or) => {
                    self.compile_node(left)?;
                    let end = self.emit(Opcode::JumpIfTrue(0));
                    self.emit(Opcode::Pop);
                    let r = self.compile_node(right)?;
                    self.replace(end, Opcode::JumpIfTrue(r - end));

                    Ok(r)
                }
                Operator::Logical(LogicalOperator::And) => {
                    self.compile_node(left)?;
                    let end = self.emit(Opcode::JumpIfFalse(0));
                    self.emit(Opcode::Pop);
                    let r = self.compile_node(right)?;
                    self.replace(end, Opcode::JumpIfFalse(r - end));

                    Ok(r)
                }
                Operator::Logical(LogicalOperator::NullishCoalescing) => {
                    self.compile_node(left)?;
                    let end = self.emit(Opcode::JumpIfNotNull(0));
                    self.emit(Opcode::Pop);
                    let r = self.compile_node(right)?;
                    self.replace(end, Opcode::JumpIfNotNull(r - end));

                    Ok(r)
                }
                Operator::Comparison(ComparisonOperator::In) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::In))
                }
                Operator::Comparison(ComparisonOperator::NotIn) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    self.emit(Opcode::In);
                    Ok(self.emit(Opcode::Not))
                }
                Operator::Comparison(ComparisonOperator::LessThan) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Less))
                }
                Operator::Comparison(ComparisonOperator::LessThanOrEqual) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::LessOrEqual))
                }
                Operator::Comparison(ComparisonOperator::GreaterThan) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::More))
                }
                Operator::Comparison(ComparisonOperator::GreaterThanOrEqual) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::MoreOrEqual))
                }
                Operator::Arithmetic(ArithmeticOperator::Add) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Add))
                }
                Operator::Arithmetic(ArithmeticOperator::Subtract) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Subtract))
                }
                Operator::Arithmetic(ArithmeticOperator::Multiply) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Multiply))
                }
                Operator::Arithmetic(ArithmeticOperator::Divide) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Divide))
                }
                Operator::Arithmetic(ArithmeticOperator::Modulus) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Modulo))
                }
                Operator::Arithmetic(ArithmeticOperator::Power) => {
                    self.compile_node(left)?;
                    self.compile_node(right)?;
                    Ok(self.emit(Opcode::Exponent))
                }
                _ => Err(CompilerError::UnknownBinaryOperator {
                    operator: operator.to_string(),
                }),
            },
            Node::BuiltIn { kind, arguments } => match kind {
                BuiltInFunction::Len => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Len);
                    self.emit(Opcode::Rot);
                    Ok(self.emit(Opcode::Pop))
                }
                BuiltInFunction::Date => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::ParseDateTime))
                }
                BuiltInFunction::Time => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::ParseTime))
                }
                BuiltInFunction::Duration => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::ParseDuration))
                }
                BuiltInFunction::StartsWith => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::StartsWith))
                }
                BuiltInFunction::EndsWith => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::EndsWith))
                }
                BuiltInFunction::Contains => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::Contains))
                }
                BuiltInFunction::Matches => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::Matches))
                }
                BuiltInFunction::FuzzyMatch => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::FuzzyMatch))
                }
                BuiltInFunction::Split => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;

                    Ok(self.emit(Opcode::Split))
                }
                BuiltInFunction::Extract => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::Extract))
                }
                BuiltInFunction::Flatten => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Flatten))
                }
                BuiltInFunction::Upper => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Uppercase))
                }
                BuiltInFunction::Lower => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Lowercase))
                }
                BuiltInFunction::Abs => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Abs))
                }
                BuiltInFunction::Avg => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Average))
                }
                BuiltInFunction::Median => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Median))
                }
                BuiltInFunction::Mode => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Mode))
                }
                BuiltInFunction::Max => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Max))
                }
                BuiltInFunction::Min => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Min))
                }
                BuiltInFunction::Sum => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Sum))
                }
                BuiltInFunction::Floor => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Floor))
                }
                BuiltInFunction::Ceil => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Ceil))
                }
                BuiltInFunction::Round => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Round))
                }
                BuiltInFunction::Rand => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Random))
                }
                BuiltInFunction::String => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::TypeConversion(TypeConversionKind::String)))
                }
                BuiltInFunction::Number => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::TypeConversion(TypeConversionKind::Number)))
                }
                BuiltInFunction::Bool => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::TypeConversion(TypeConversionKind::Bool)))
                }
                BuiltInFunction::IsNumeric => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::TypeCheck(TypeCheckKind::Numeric)))
                }
                BuiltInFunction::Type => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::GetType))
                }
                BuiltInFunction::Keys => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Keys))
                }
                BuiltInFunction::Values => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::Values))
                }
                BuiltInFunction::StartOf | BuiltInFunction::EndOf => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.compile_argument(kind, arguments, 1)?;
                    Ok(self.emit(Opcode::DateFunction(kind.into())))
                }
                BuiltInFunction::DayOfWeek
                | BuiltInFunction::DayOfMonth
                | BuiltInFunction::DayOfYear
                | BuiltInFunction::WeekOfYear
                | BuiltInFunction::MonthOfYear
                | BuiltInFunction::MonthString
                | BuiltInFunction::WeekdayString
                | BuiltInFunction::Year
                | BuiltInFunction::DateString => {
                    self.compile_argument(kind, arguments, 0)?;
                    Ok(self.emit(Opcode::DateManipulation(kind.into())))
                }
                BuiltInFunction::All => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    let mut loop_break: usize = 0;
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        loop_break = c.emit(Opcode::JumpIfFalse(0));
                        c.emit(Opcode::Pop);
                        Ok(())
                    })?;
                    let e = self.emit(Opcode::Push(Variable::Bool(true)));
                    self.replace(loop_break, Opcode::JumpIfFalse(e - loop_break));
                    Ok(self.emit(Opcode::End))
                }
                BuiltInFunction::None => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    let mut loop_break: usize = 0;
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        c.emit(Opcode::Not);
                        loop_break = c.emit(Opcode::JumpIfFalse(0));
                        c.emit(Opcode::Pop);
                        Ok(())
                    })?;
                    let e = self.emit(Opcode::Push(Variable::Bool(true)));
                    self.replace(loop_break, Opcode::JumpIfFalse(e - loop_break));
                    Ok(self.emit(Opcode::End))
                }
                BuiltInFunction::Some => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    let mut loop_break: usize = 0;
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        loop_break = c.emit(Opcode::JumpIfTrue(0));
                        c.emit(Opcode::Pop);
                        Ok(())
                    })?;
                    let e = self.emit(Opcode::Push(Variable::Bool(false)));
                    self.replace(loop_break, Opcode::JumpIfTrue(e - loop_break));
                    Ok(self.emit(Opcode::End))
                }
                BuiltInFunction::One => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        c.emit_cond(|c| {
                            c.emit(Opcode::IncrementCount);
                        });
                        Ok(())
                    })?;
                    self.emit(Opcode::GetCount);
                    self.emit(Opcode::Push(Variable::Number(dec!(1))));
                    self.emit(Opcode::Equal);
                    Ok(self.emit(Opcode::End))
                }
                BuiltInFunction::Filter => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        c.emit_cond(|c| {
                            c.emit(Opcode::IncrementCount);
                            c.emit(Opcode::Pointer);
                        });
                        Ok(())
                    })?;
                    self.emit(Opcode::GetCount);
                    self.emit(Opcode::End);
                    Ok(self.emit(Opcode::Array))
                }
                BuiltInFunction::Map => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        Ok(())
                    })?;
                    self.emit(Opcode::GetLen);
                    self.emit(Opcode::End);
                    Ok(self.emit(Opcode::Array))
                }
                BuiltInFunction::FlatMap => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        Ok(())
                    })?;
                    self.emit(Opcode::GetLen);
                    self.emit(Opcode::End);
                    self.emit(Opcode::Array);
                    Ok(self.emit(Opcode::Flatten))
                }
                BuiltInFunction::Count => {
                    self.compile_argument(kind, arguments, 0)?;
                    self.emit(Opcode::Begin);
                    self.emit_loop(|c| {
                        c.compile_argument(kind, arguments, 1)?;
                        c.emit_cond(|c| {
                            c.emit(Opcode::IncrementCount);
                        });
                        Ok(())
                    })?;
                    self.emit(Opcode::GetCount);
                    Ok(self.emit(Opcode::End))
                }
            },
        }
    }
}