ailang/
compiler.rs

1#![allow(dead_code)]
2use std::fmt::{Display, Formatter, Result as FmtResult};
3use std::collections::{HashMap, HashSet};
4use unicode_segmentation::{UnicodeSegmentation};
5use itertools::Itertools;
6
7use std::sync::atomic::{AtomicBool, Ordering};
8
9use crate::token::{TokenType};
10use crate::token::{Literal as LexLiteral};
11use crate::ast::{Arg as AstArg, *};
12use crate::error::Error;
13
14#[derive(Clone, Debug, PartialEq)]
15pub enum Value {
16    Number(f64),
17    String(String),
18    Bool(bool),
19    Nil,
20}
21
22impl Value {
23    pub fn truthy(&self) -> bool {
24        match self {
25            Value::Number(n) => *n != 0.0,
26            Value::String(s) => s.len() > 0,
27            Value::Bool(b) => *b,
28            Value::Nil => false,
29        }
30    }
31    
32    pub fn is_num(&self) -> bool {
33        if let Value::Number(_) = self {true} else {false}
34    }
35
36    pub fn is_str(&self) -> bool {
37        if let Value::String(_) = self {true} else {false}
38    }
39}
40
41impl Display for Value {
42    fn fmt(&self, f: &mut Formatter) -> FmtResult {
43        match self {
44            Value::Number(n) => write!(f, "{}", n),
45            Value::String(s) => write!(f, "\"{}\"", s),
46            Value::Bool(b) => write!(f, "{}", b),
47            Value::Nil => write!(f, "nil"),
48        }
49    }
50}
51
52impl std::str::FromStr for Value {
53    type Err = Error;
54    fn from_str(value: &str) -> Result<Value, Error> {
55        if value.as_bytes()[0] == b'"' {
56            Ok(Value::String(value.to_string()))
57        } else if value.as_bytes()[0].is_ascii_digit() {
58            value.parse().map(|n| Value::Number(n)).map_err(|_| Error::IRParse {
59                line: 0,
60                msg: "Invalid word, expected number".into(),
61            })
62        } else if value == "true" || value == "false" {
63            Ok(Value::Bool(value == "true"))
64        } else if value == "nil" {
65            Ok(Value::Nil)
66        } else {
67            Err(Error::IRParse {
68                line: 0,
69                msg: format!("Unrecognized value: '{}'", value),
70            })
71        }
72    }
73}
74
75#[derive(Clone)]
76pub enum Op {
77    // Use(String),
78
79    Load(usize), // relative index of the variable on the stack
80    Store(usize),
81    Get(String),
82    Set(String),
83    Push(Value),
84    Pop,
85    Dup,
86
87    Add,
88    Sub,
89    Mul,
90    Div,
91    Mod,
92    Exp,
93    Neg,
94    Abs,
95
96    And,
97    Or,
98    Not,
99    Xor,
100
101    Eq,
102    Ne,
103    Lt,
104    Le,
105    Gt,
106    Ge,
107
108    Jump(isize), // absolute position
109    JumpUnless(isize),
110    JumpIf(isize),
111
112    Label(String),
113    Call(String, usize),
114    CallParallel(Vec<(String, usize)>), // first usize is reverse offset. Will always be reverse
115    CallRace(Vec<(String, usize)>),
116    // StartPara(usize, usize), // call count, total arg count
117    Yield,
118    Return,
119}
120
121impl Op {
122    pub fn is_call(&self) -> bool {
123        match self {
124            Op::Call(_, _) | Op::CallParallel(_) | Op::CallRace(_) => true,
125            _ => false,
126        }
127    }
128}
129
130fn format_calls(calls: &[(String, usize)]) -> String {
131    let mut out = String::new();
132    for (name, arity) in calls {
133        out += &format!(" \"{}\" {}", name, arity);
134    }
135    out
136}
137
138impl Display for Op {
139    fn fmt(&self, f: &mut Formatter) -> FmtResult {
140        use Op::*;
141        match self {
142            // Use(s) => write!(f, "use \"{}\"", s),
143            Load(a) => write!(f, "load {}", a),
144            Store(a) => write!(f, "store {}", a),
145            Get(s) => write!(f, "get \"{}\"", s),
146            Set(s) => write!(f, "get \"{}\"", s),
147            Push(v) => write!(f, "push {}", v),
148            Jump(a) => write!(f, "jump {}", a),
149            JumpUnless(a) => write!(f, "jump_unless {}", a),
150            JumpIf(a) => write!(f, "jump_if {}", a),
151            Label(s) => write!(f, "{}:", s),
152            Call(s, p) => write!(f, "call \"{}\" {}", s, p),
153            // StartPara(n, m) => write!(f, "start_para {} {}", n, m),
154            CallParallel(calls) => write!(f, "call_parallel{}", format_calls(calls)),
155            CallRace(calls) => write!(f, "call_race{}", format_calls(calls)),
156            Return => write!(f, "return"),
157            Yield => write!(f, "yield"),
158            Pop => write!(f, "pop"),
159            Dup => write!(f, "dup"),
160            Add => write!(f, "add"),
161            Sub => write!(f, "sub"),
162            Mul => write!(f, "mul"),
163            Div => write!(f, "div"),
164            Mod => write!(f, "mod"),
165            Exp => write!(f, "exp"),
166            Neg => write!(f, "neg"),
167            Abs => write!(f, "abs"),
168            And => write!(f, "and"),
169            Or => write!(f, "or"),
170            Not => write!(f, "not"),
171            Xor => write!(f, "xor"),
172            Eq => write!(f, "eq"),
173            Ne => write!(f, "ne"),
174            Lt => write!(f, "lt"),
175            Le => write!(f, "le"),
176            Gt => write!(f, "gt"),
177            Ge => write!(f, "ge"),
178        }
179    }
180}
181
182fn shell_split(input: &str) -> Vec<&str> {
183    let mut parts = Vec::new();
184    let mut start = 0;
185    let mut quoted = false;
186    let mut last_space = false;
187    
188    for (i, g) in input.grapheme_indices(true) {
189        if last_space {
190            last_space = false;
191            start += 1;
192            continue;
193        }
194        if g == "\"" {
195            quoted = !quoted;
196            continue;
197        }
198        if g == " " && !quoted {
199            last_space = true;
200            parts.push(&input[start..i]);
201            start = i+1;
202        }
203    }
204
205    parts.push(&input[start..]);
206
207    parts
208}
209
210fn parse_parallel_args(input: &[&str]) -> Result<Vec<(String, usize)>, Error> {
211    let (calls, rest) = input.as_chunks::<2>();
212    if rest.len()  != 0 {
213        return Err(Error::IRParse{line: 0, msg: format!("Every call in parallel call requires an arity")});
214    }
215    
216    let mut calls_out = Vec::new();
217    for call in calls {
218        if call[0].as_bytes()[0]  != b'"' {
219            return Err(Error::IRParse{line: 0, msg: "parallel calls must take a string".into()});
220        } else if !call[0][1..].contains("\"") {
221            return Err(Error::IRParse{line: 0, msg: "Unterminated string in parallel_call".into()});
222        } else {
223            let name = call[0][1..call[0].len()-1].to_string();
224
225            let arity = call[1].parse().map_err(|_| Error::IRParse {
226                line: 0,
227                msg: "Calls require the arity as a second argument".into(),
228            })?;
229            calls_out.push((name, arity));
230        }
231    }
232    Ok(calls_out)
233}
234
235macro_rules! expect_len {
236    ($list:expr, $index:expr, $name:expr) => {
237        {
238            $list.get($index).ok_or(Error::IRParse {
239                line: 0,
240                msg: format!("'{}' expects {} arguments", $name, $index),
241            })?
242        }
243    }
244}
245
246
247macro_rules! parse_string {
248    ($value:expr, $op:expr) => {
249        {
250            if !$value.starts_with("\"") {
251                Err(Error::IRParse{line: 0, msg: format!("'{}' must take a string", $op)})
252            } else if $value.len() < 2 || !$value.ends_with("\"") {
253                Err(Error::IRParse{line: 0, msg: format!("Unterminated string in '{}'", $op)})
254            } else {
255                Ok($value[1..$value.len()-1].to_string())
256            }
257        }
258    }
259}
260
261impl std::str::FromStr for Op {
262    type Err = Error;
263    fn from_str(value: &str) -> Result<Op, Error> {
264        // let parts = value.split(" ").collect::<Vec<&str>>();
265        let parts = shell_split(value);
266        if parts.len() == 0 {
267            return Err(Error::IRParse {
268                line: 0,
269                msg: "No instruction present".into(),
270            })
271        }
272        match parts[0] {
273            "load" => expect_len!(parts, 1, "load").parse().map(|a| Op::Load(a)).map_err(|_| Error::IRParse {
274                line: 0,
275                msg: format!("Invalid stack address: '{}'", parts[1]),
276            }),
277            "store" => expect_len!(parts, 1, "store").parse().map(|a| Op::Store(a)).map_err(|_| Error::IRParse {
278                line: 0,
279                msg: format!("Invalid stack address: '{}'", parts[1]),
280            }),
281            "get" => Ok(Op::Get(parse_string!(expect_len!(parts, 1, "get"), "get")?)),
282            "set" => Ok(Op::Set(parse_string!(expect_len!(parts, 1, "set"), "set")?)),
283            "push" => expect_len!(parts, 1, "push").parse().map(|v| Op::Push(v)),
284            "jump" => expect_len!(parts, 1, "jump").parse().map(|a| Op::Jump(a)).map_err(|_| Error::IRParse {
285                line: 0,
286                msg: format!("Invalid stack address: '{}'", parts[1]),
287            }),
288            "jump_unless" => expect_len!(parts, 1, "jump_unless").parse().map(|a| Op::JumpUnless(a)).map_err(|_| Error::IRParse {
289                line: 0,
290                msg: format!("Invalid stack address: '{}'", parts[1]),
291            }),
292            "jump_if" => expect_len!(parts, 1, "jump_if").parse().map(|a| Op::JumpIf(a)).map_err(|_| Error::IRParse {
293                line: 0,
294                msg: format!("Invalid stack address: '{}'", parts[1]),
295            }),
296            "call" => {
297                let arity = expect_len!(parts, 2, "call").parse().map_err(|_| Error::IRParse {
298                    line: 0,
299                    msg: "Calls require the arity as a second argument".into(),
300                })?;
301                let name = parse_string!(parts[1], "call")?;
302                Ok(Op::Call(name, arity))
303            }
304            "call_parallel" => Ok(Op::CallParallel(parse_parallel_args(&parts[1..])?)),
305            "call_race" => Ok(Op::CallRace(parse_parallel_args(&parts[1..])?)),
306            "return" => Ok(Op::Return),
307            "yield" => Ok(Op::Yield),
308            "pop" => Ok(Op::Pop),
309            "dup" => Ok(Op::Dup),
310            "add" => Ok(Op::Add),
311            "sub" => Ok(Op::Sub),
312            "mul" => Ok(Op::Mul),
313            "div" => Ok(Op::Div),
314            "mod" => Ok(Op::Mod),
315            "exp" => Ok(Op::Exp),
316            "neg" => Ok(Op::Neg),
317            "abs" => Ok(Op::Abs),
318            "and" => Ok(Op::And),
319            "or" => Ok(Op::Or),
320            "not" => Ok(Op::Not),
321            "xor" => Ok(Op::Xor),
322            "eq" => Ok(Op::Eq),
323            "ne" => Ok(Op::Ne),
324            "lt" => Ok(Op::Lt),
325            "le" => Ok(Op::Le),
326            "gt" => Ok(Op::Gt),
327            "ge" => Ok(Op::Ge),
328            _ => {
329                if parts[0].ends_with(":") {
330                    Ok(Op::Label(parts[0][..parts[0].len()-1].to_string()))
331                } else{
332                    Err(Error::IRParse {
333                        line: 0, // This will need to be backpatched.
334                        msg: format!("Invalid op: '{}'", parts[0])
335                    })
336                }
337            }
338        }
339    }
340}
341
342pub trait Callable: Send + Sync {
343    fn call(&mut self) -> Result<bool, Error>;
344    fn terminate(&mut self) -> Result<(), Error> {Ok(())}
345    // fn arity(&self) -> usize;
346}
347
348pub trait CallableGenerator: Send + Sync {
349    fn generate(&mut self, args: Vec<Value>) -> Result<Box<dyn Callable>, Error>;
350    fn check_syntax(&self, args: Vec<Arg>) -> Result<(), Error>;
351}
352
353#[allow(unused_variables)]
354pub trait Prop: Send + Sync {
355    fn get(&self) -> Result<Value, Error>;
356    fn set(&mut self, val: Value) -> Result<(), Error> {Ok(())}
357    fn settable(&self) -> Result<bool, Error> {Ok(false)}
358}
359
360#[derive(Debug, PartialEq, Clone)]
361pub enum Arg {
362    Word(String),
363    Value,
364}
365
366impl Arg {
367    pub fn is_value(&self) -> bool {
368        if let Arg::Value = self {
369            true
370        } else {
371            false
372        }
373    }
374
375    pub fn get_word(&self) -> Option<&str> {
376        if let Arg::Word(s) = self {
377            Some(&s)
378        } else {
379            None
380        }
381    }
382}
383
384impl Display for Arg {
385    fn fmt(&self, f: &mut Formatter) -> FmtResult {
386        match self {
387            Arg::Word(s) => write!(f, "'{}'", s),
388            Arg::Value => write!(f, "a value"),
389        }
390    }
391}
392
393
394#[derive(Clone)]
395struct GroupData {
396    name: String,
397    // address: isize,
398    params: Vec<Arg>,
399}
400
401#[derive(Clone)]
402struct CompiledGroup {
403    data: GroupData,
404    code: Vec<Op>
405}
406
407impl CallableGenerator for CompiledGroup {
408    // fn call(&mut self, _args: Vec<Value>) -> bool {
409    //     panic!("This type only exists for the compiler. 'call' should never be called.")
410    // }
411    // fn terminate(&mut self) {
412    //     panic!("This type only exists for the compiler. 'terminate' should never be called.")
413    // }
414    fn check_syntax(&self, args: Vec<Arg>) -> Result<(), Error> {
415        if args.len() != self.data.params.len() {
416            return Err(Error::Call(format!("Call to '{}' expected {} arguments but got {}", 
417                                            self.data.name, 
418                                            self.data.params.len(), 
419                                            args.len())));
420        }
421        for (i, (param, args)) in self.data.params.iter().zip(args.iter()).enumerate() {
422            if param != args {
423                return Err(Error::Call(format!("Argument at position {} should be {}", i, param)));
424            }
425        } 
426
427        Ok(())
428    }
429    fn generate(&mut self, _args: Vec<Value>) -> Result<Box<dyn Callable>, Error> {
430        panic!("This type only exists for the compiler. 'arity' should never be called.")
431    }
432}
433
434pub struct Program {
435    pub code: Vec<Op>,
436    pub callables: HashMap<String, Box<dyn CallableGenerator>>,
437    pub props: HashMap<String, Box<dyn Prop>>,
438}
439
440impl Program {
441    pub fn export(&self) -> String {
442        self.code.iter().join("\n")
443    }
444}
445
446
447pub struct Compiler {
448    groups: HashMap<String, CompiledGroup>,
449    instructions: Vec<Op>,
450    callables: HashMap<String, Box<dyn CallableGenerator>>,
451    properties: HashMap<String, Box<dyn Prop>>,
452    allowed_props: HashSet<String>,
453
454    variables: Vec<HashMap<String, usize>>,
455    errors: Vec<Error>,
456    in_progress: AtomicBool,
457}
458
459unsafe impl Send for Compiler {}
460unsafe impl Sync for Compiler {}
461
462impl<'a> Compiler {
463    pub fn new() -> Compiler {
464        Compiler {
465            groups: HashMap::new(),
466            instructions: Vec::new(),
467            callables: HashMap::new(),
468            properties: HashMap::new(),
469            allowed_props: HashSet::new(),
470            variables: vec![HashMap::new()],
471            errors: Vec::new(),
472            in_progress: AtomicBool::new(false),
473        }
474    }
475
476    pub fn package_program(&mut self, code: Vec<Op>) -> Program {
477        Program {
478            code,
479            callables: std::mem::take(&mut self.callables),
480            props: std::mem::take(&mut self.properties),
481        }
482    }
483
484    pub fn compile_nonconsuming(&mut self, ast: Vec<Stmt<'a>>) -> Result<Vec<Op>, Vec<Error>> {
485        self.in_progress.store(true, Ordering::Release);
486
487        let (uses, program): (Vec<Stmt<'a>>, _) = ast.into_iter().partition(|stmt| {
488            if let Stmt::Use(_) = stmt {true} else {false}
489        });
490
491        for us in uses {
492            us.accept_mut(self);
493        }
494
495        let program = self.isolate(move |this| {
496            for stmt in program.iter() {
497                stmt.accept_mut(this);
498            }
499        });
500
501        let group_code = self.isolate(|this| {
502            for (_name, group) in this.groups.iter_mut() {
503                this.instructions.extend(group.code.drain(..));
504            }
505        });
506        
507        self.instructions.push(Op::Jump(group_code.len() as isize + 1));
508        self.instructions.extend(group_code);
509        self.instructions.extend(program);
510        
511        // for inst in program.iter() {
512        //     inst.accept_mut(&mut self);
513        // }
514
515
516        
517        let res = if self.errors.is_empty() {
518            Ok(std::mem::take(&mut self.instructions))
519        } else {
520            Err(std::mem::take(&mut self.errors))
521        };
522
523        self.in_progress.store(false, Ordering::Release);
524        res
525    }
526
527    pub fn compile(mut self, ast: Vec<Stmt<'a>>) -> Result<Program, Vec<Error>> {
528        // No need to worry about updating `in_progress`, since this completely consumes the
529        // compiler
530        let code = self.compile_nonconsuming(ast)?;
531        let res = self.package_program(code);
532
533        Ok(res)
534    }
535
536    pub fn register_callable(&mut self, name: &str, callable: Box<dyn CallableGenerator>) -> Result<(), Error> {
537        if self.in_progress.load(Ordering::Acquire) {
538            return Err(Error::CompilerActive);
539        }
540        if self.callables.contains_key(name) {
541            return Err(Error::DuplicateCallable(name.into()));
542        }
543        self.callables.insert(name.to_string(), callable);
544        Ok(())
545    }
546
547    pub fn register_property(&mut self, name: &str, prop: Box<dyn Prop>) -> Result<(), Error> {
548        if self.in_progress.load(Ordering::Acquire) {
549            return Err(Error::CompilerActive);
550        }
551        if self.properties.contains_key(name) {
552            return Err(Error::DuplicateProperty(name.into()));
553        }
554        self.properties.insert(name.to_string(), prop);
555        Ok(())
556    }
557
558    fn declare_var(&mut self, name: &'a str) -> usize {
559        let scope = unsafe {self.variables.last_mut().unwrap_unchecked()};
560        if scope.contains_key(name) {
561            return scope[name];
562        }
563        let idx = scope.len();
564        scope.insert(name.to_string(), idx);
565        idx
566    }
567
568    fn begin_scope(&mut self) {
569        self.variables.push(HashMap::new());
570    }
571
572    fn end_scope(&mut self) {
573        self.variables.pop();
574    }
575
576    fn get_var(&mut self, name: &'a str) -> Result<usize, Error> {
577        let scope = unsafe {self.variables.last_mut().unwrap_unchecked()};
578        scope.get(name).map(|i| *i).ok_or(Error::Compile{line: 0, msg: format!("Variable '{}' used before it was declared", name)})
579    }
580
581    // FIXME if useful, change output to Result<_> Halting parsing may be useful?
582    fn isolate<F: FnMut(&mut Self)>(&mut self, mut f: F) -> Vec<Op> {
583        let current_program = std::mem::take(&mut self.instructions);
584        f(self);
585        let sub_program = std::mem::replace(&mut self.instructions, current_program);
586        sub_program
587    }
588
589    fn current_ip(&self) -> isize {
590        self.instructions.len() as isize
591    }
592}
593
594impl<'a> ExprVisitorMut<'a, ()> for Compiler {
595    fn visit_variable_expr(&mut self, expr: &Variable<'a>) {
596        let LexLiteral::Ident(name) = expr.name.literal.unwrap() else {
597            self.errors.push(Error::Compile{line: 0, msg: "Variable was somehow called without an associated identifier".into()});
598            return;
599        };
600
601        if self.properties.contains_key(name) {
602            if !self.allowed_props.contains(name) {
603                self.errors.push(Error::UndeclaredProperty(name.into()));
604                return;
605            }
606            self.instructions.push(Op::Get(name.to_string()));
607            return;
608        }
609
610        let idx = match self.get_var(name) {
611            Ok(idx) => idx,
612            Err(e) => {
613                self.errors.push(e);
614                return;
615            }
616        };
617        self.instructions.push(Op::Load(idx));
618    }
619    
620    fn visit_literal_expr(&mut self, expr: &Literal<'a>) {
621        let value = match expr.value {
622            LexLiteral::String(s) => Value::String(s.into()),
623            LexLiteral::Number(n) => Value::Number(n),
624            LexLiteral::Bool(b) => Value::Bool(b),
625            LexLiteral::Nil => Value::Nil,
626            LexLiteral::Ident(_) => panic!("You are actually using literal identifiers, stupid!"),
627        };
628
629        self.instructions.push(Op::Push(value))
630    }
631    
632    fn visit_grouping_expr(&mut self, expr: &Grouping<'a>) {
633        expr.expression.accept_mut(self);
634        if expr.abs {
635            self.instructions.push(Op::Abs);
636        }
637    }
638
639    fn visit_unary_expr(&mut self, expr: &Unary<'a>) {
640        expr.right.accept_mut(self);
641        match expr.op.ty {
642            TokenType::Not => self.instructions.push(Op::Not),
643            TokenType::Minus => self.instructions.push(Op::Neg),
644            _ => self.errors.push(Error::Compile{line: 0, msg: "Invalid unary operator".into()}),
645        }
646    }
647
648    fn visit_binary_expr(&mut self, expr: &Binary<'a>) {
649        expr.left.accept_mut(self);
650        expr.right.accept_mut(self);
651
652        match expr.op.ty {
653            TokenType::BangEqual => self.instructions.push(Op::Ne),
654            TokenType::EqualEqual => self.instructions.push(Op::Eq),
655            TokenType::Greater => self.instructions.push(Op::Gt),
656            TokenType::GreaterEqual => self.instructions.push(Op::Ge),
657            TokenType::Less => self.instructions.push(Op::Lt),
658            TokenType::LessEqual => self.instructions.push(Op::Le),
659            TokenType::Minus => self.instructions.push(Op::Sub),
660            TokenType::Plus => self.instructions.push(Op::Add),
661            TokenType::Slash => self.instructions.push(Op::Div),
662            TokenType::Star => self.instructions.push(Op::Mul),
663            TokenType::Percent => self.instructions.push(Op::Mod),
664            TokenType::Caret => self.instructions.push(Op::Exp),
665            _ => self.errors.push(Error::Compile{line: 0, msg: "Invalid binary operator".into()}),
666        }
667    }
668
669    // binary_expr!('a, or, xor, logical, [Or]);
670    // binary_expr!('a, and, equality, logical, [And]);
671    fn visit_logical_expr(&mut self, expr: &Logical<'a>) {
672        expr.left.accept_mut(self);
673        self.instructions.push(Op::Dup);
674
675        match expr.op.ty {
676            TokenType::And => {
677                let sub_program = self.isolate(|this| {
678                    expr.right.accept_mut(this);
679                });
680                self.instructions.push(Op::JumpUnless(sub_program.len() as isize + 1));
681                self.instructions.extend(sub_program);
682                self.instructions.push(Op::And);
683            }
684            TokenType::Or => {
685                let sub_program = self.isolate(|this| {
686                    expr.left.accept_mut(this);
687                });
688                self.instructions.push(Op::JumpIf(sub_program.len() as isize + 1));
689                self.instructions.extend(sub_program);
690                self.instructions.push(Op::Or);
691            }
692            TokenType::Xor => {
693                expr.right.accept_mut(self);
694                self.instructions.push(Op::Xor);
695            }
696            _ => {
697                self.errors.push(Error::Compile{line: 0, msg: "Invalid logical operator".into()})
698            }
699        }
700    }
701}
702
703impl<'a> StmtVisitorMut<'a, ()> for Compiler {
704    fn visit_var_stmt(&mut self, stmt: &Var<'a>) {
705        stmt.value.accept_mut(self);
706        let LexLiteral::Ident(name) = stmt.name.literal.unwrap() else {
707            self.errors.push(Error::Compile{line: 0, msg: "Invalid variable name".into()});
708            return;
709        };
710
711        if let Some(prop) = self.properties.get(name) {
712            match prop.settable() {
713                Ok(false) => {
714                    self.errors.push(Error::Compile{line: 0, msg: format!("External property '{}' not settable", name)});
715                    return;
716                }
717                Err(e) => {
718                    self.errors.push(e);
719                    return;
720                }
721                _ => {}
722            }
723            self.instructions.push(Op::Set(name.into()));
724        } else {
725            let idx = self.declare_var(name);
726            self.instructions.push(Op::Store(idx));
727        }
728    }
729
730    fn visit_use_stmt(&mut self, stmt: &Use<'a>) {
731        let LexLiteral::Ident(name) = stmt.name.literal.unwrap() else {
732            self.errors.push(Error::Compile{line: 0, msg: "'use' statements must only use identifiers".into()});
733            return;
734        };
735
736        if !self.properties.contains_key(name) {
737            self.errors.push(Error::UnknownProperty(name.into()));
738            return;
739        }
740
741        self.allowed_props.insert(name.into());
742    }
743    
744    fn visit_exec_stmt(&mut self, stmt: &Exec<'a>) {
745        let name = stmt.name.lexeme;
746        if !self.groups.contains_key(name) && !self.callables.contains_key(name) {
747            self.errors.push(Error::UnknownCallable(name.into()));
748            return;
749        } 
750
751        let arg_kinds = stmt.args.iter().map(|a| {
752            match a {
753                AstArg::Word(w) => Arg::Word(w.lexeme.into()),
754                AstArg::Value(_) => Arg::Value,
755            }
756        }).collect();
757
758        if let Some(callable) = self.groups.get(name) {
759            if let Err(e) = callable.check_syntax(arg_kinds) {
760                self.errors.push(e);
761                return;
762            }
763        } else {
764            if let Err(e) = self.callables[name].check_syntax(arg_kinds) {
765                self.errors.push(e);
766                return;
767            }
768        }
769
770        let mut arity = 0;
771        for arg in stmt.args.iter() {
772            if let AstArg::Value(v) = arg {
773                arity += 1;
774                v.accept_mut(self);
775            }
776        }
777
778        self.instructions.push(Op::Call(name.into(), arity));
779    }
780
781
782    fn visit_parallel_stmt(&mut self, stmt: &Parallel<'a>) {
783        let mut call_args = Vec::new();
784        for call in stmt.calls.iter() {
785            let name = call.name.lexeme;
786            if !self.groups.contains_key(name) && !self.callables.contains_key(name) {
787                self.errors.push(Error::UnknownCallable(name.into()));
788                return;
789            } 
790        
791            let arg_kinds = call.args.iter().map(|a| {
792                match a {
793                    AstArg::Word(w) => Arg::Word(w.lexeme.into()),
794                    AstArg::Value(_) => Arg::Value,
795                }
796            }).collect();
797
798            let arity = call.args.iter().filter(|a| if let AstArg::Value(_) = a {true} else {false}).count();
799            let name = if let Some(callable) = self.groups.get(name) {
800                if let Err(e) = callable.check_syntax(arg_kinds) {
801                    self.errors.push(e);
802                    return;
803                }
804                name.to_string()
805            } else {
806                if let Err(e) = self.callables[name].check_syntax(arg_kinds.clone()) {
807                    self.errors.push(e);
808                    return;
809                }
810
811                let anonymous_name = format!("#{}", name);
812                
813                if self.groups.contains_key(name) {
814                    continue;
815                }
816
817                let external_group = CompiledGroup {
818                    data: GroupData {
819                        name: anonymous_name.clone(),
820                        params: arg_kinds,
821                    },
822                    code: vec![
823                        // There's no need to push call arguments on the stack since the groups args 
824                        // are already in the right order for the call, and the immediate return
825                        // will ensure the either the stack frame is discarded or the context is
826                        // destroyed. Either way, the stack is well-formed.
827                        Op::Label(anonymous_name.clone()),
828                        Op::Call(name.to_string(), arity),
829                        Op::Return,
830                    ]
831                };
832
833                self.groups.insert(anonymous_name.clone(), external_group);
834
835                anonymous_name
836            };
837            call_args.push((name, arity));
838        }
839        
840        let prep = self.isolate(|this| {
841            for call in stmt.calls.iter().rev() {
842                for arg in call.args.iter().rev() {
843                    match arg {
844                        AstArg::Value(expr) => expr.accept_mut(this),
845                        AstArg::Word(_) => continue,
846                    }
847                }
848            }
849        });
850        // let offset = prep.len();
851        // self.instructions.push(Op::StartPara(stmt.calls.len(), call_args.len()));
852        self.instructions.extend(prep);
853        self.instructions.push(if stmt.race {
854            Op::CallRace(call_args)
855        } else {
856            Op::CallParallel(call_args)
857        });
858        // Just have the parallel calls have a +1 at the end. It's either this or be even more
859        // opaque with the unnnecessary StartPara thing.
860        // self.instructions.push(Op::Jump(-(offset as isize + 1)));
861    }
862
863    fn visit_group_stmt(&mut self, stmt: &Group<'a>) {
864        self.begin_scope();
865        
866        let name = stmt.name.lexeme.to_string();
867    
868        if self.callables.contains_key(&name) {
869            self.errors.push(Error::DuplicateCallable(name));
870            return;
871        }
872
873        let params: Vec<_> = stmt.params.iter().map(|t| {
874            match t.ty {
875                TokenType::Word => Arg::Word(t.lexeme.to_string()),
876                TokenType::Ident => {
877                    let LexLiteral::Ident(name) = t.literal.unwrap() else {unreachable!()};
878                    self.declare_var(name);
879                    Arg::Value
880                }
881                _ => unreachable!(),
882            }
883        }).collect();
884        
885
886        let body = self.isolate(|this| {
887            this.instructions.push(Op::Label(name.clone()));
888            for stmt in stmt.statements.iter() {
889                stmt.accept_mut(this);
890            }
891            for _ in 0..params.len() {
892                this.instructions.push(Op::Pop);
893            }
894            this.instructions.push(Op::Return);
895        });
896    
897        let group = CompiledGroup {
898            data: GroupData {
899                name: name.clone(),
900                params,
901                // address: self.current_ip(),
902            },
903            code: body,
904        };
905        
906        // self.instructions.extend(body);
907        self.groups.insert(name.clone(), group);
908
909        self.end_scope();
910    }
911
912
913    fn visit_if_stmt(&mut self, stmt: &If<'a>) {
914        stmt.condition.accept_mut(self);
915        if stmt.invert {
916            self.instructions.push(Op::Not);
917        }
918        let then_branch = self.isolate(|this| {
919            for then in stmt.then_branch.iter() {
920                then.accept_mut(this);
921            }
922        });
923
924        let else_branch = self.isolate(|this| {
925            for els in stmt.else_branch.iter() {
926                els.accept_mut(this);
927            }
928        });
929        let then_len = then_branch.len() as isize;
930        let else_len = else_branch.len() as isize;
931
932        self.instructions.push(Op::JumpUnless(then_len + 1));
933        self.instructions.extend(then_branch);
934        self.instructions.push(Op::Jump(else_len + 1));
935    }
936
937    fn visit_while_stmt(&mut self, stmt: &While<'a>) {
938        let condition = self.isolate(|this| {
939            stmt.condition.accept_mut(this);
940            if stmt.invert {
941                this.instructions.push(Op::Not);
942            }
943        });
944        let body = self.isolate(|this| {
945            for line in stmt.body.iter() {
946                line.accept_mut(this)
947            }
948        });
949
950        let len = (condition.len() + body.len()) as isize;
951        self.instructions.extend(condition);
952        self.instructions.push(Op::JumpUnless(body.len() as isize + 2));
953        self.instructions.extend(body);
954        self.instructions.push(Op::Jump(-(len + 1)));
955
956        let sofar = self.instructions.len();
957        // backpatch any breaks
958        for (i, inst) in self.instructions.iter_mut().enumerate() {
959            if let Op::Jump(a) = inst {
960                if *a == 0 {
961                    *a = (sofar - i) as isize;
962                }
963            }
964        }
965    }
966
967    fn visit_return_stmt(&mut self, _stmt: &Return<'a>) {
968        self.instructions.push(Op::Return);
969    }
970    
971    fn visit_yield_stmt(&mut self, _stmt: &Yield<'a>) {
972        self.instructions.push(Op::Yield);
973    }
974
975    fn visit_break_stmt(&mut self, _stmt: &Break<'a>) {
976        self.instructions.push(Op::Jump(0)); // We'll use 0 to indicate that backpatching is
977                                             // necessary, since jump 0 doesn't make any sense
978    }
979}