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 Load(usize), 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), JumpUnless(isize),
110 JumpIf(isize),
111
112 Label(String),
113 Call(String, usize),
114 CallParallel(Vec<(String, usize)>), CallRace(Vec<(String, usize)>),
116 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 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 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 = 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, 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 }
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 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 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 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 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 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 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 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 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 }
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 },
903 code: body,
904 };
905
906 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 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)); }
979}