1use std::{
2 fmt::{Display, Formatter},
3 iter::Peekable,
4 mem::{swap, take},
5 println,
6 rc::Rc,
7 vec,
8};
9
10use hashbrown::HashMap;
11
12use crate::{
13 chunk::Chunk,
14 code::OpCode,
15 error::{ErrorTuple, Location, SiltError},
16 function::FunctionObject,
17 lexer::{Lexer, TokenResult},
18 token::{Operator, Token},
19 value::Value,
20};
21
22macro_rules! build_block_until_then_eat {
23 ($self:ident, $($rule:ident)|*) => {{
24 while match $self.peek()? {
25 $( Token::$rule)|* => {$self.eat(); false}
26 Token::EOF => {
27 return Err($self.error_at(SiltError::UnterminatedBlock));
28 }
29 _ =>{declaration($self)?; true}
30 } {
31 }
32 }};
33}
34
35macro_rules! build_block_until {
36 ($self:ident, $($rule:ident)|*) => {{
37 while match $self.peek()? {
38 $( Token::$rule)|* => false,
39 Token::EOF => {
40 return Err($self.error_at(SiltError::UnterminatedBlock));
41 }
42 _ =>{declaration($self)?; true}
43 } {
44 }
45 }};
46}
47
48macro_rules! scope_and_block_until {
49 ($self:ident, $($rule:ident)|*) => {{
50 begin_scope($self);
51 build_block_until!($self, $($rule)|*);
52 end_scope($self,false);
53 }};
54}
55
56macro_rules! scope_and_block_until_then_eat {
57 ($self:ident, $($rule:ident)|*) => {{
58 begin_scope($self);
59 build_block_until_then_eat!($self, $($rule)|*);
60 end_scope($self,false);
61 }};
62}
63
64macro_rules! devnote {
65 ($self:ident $message:literal) => {
66 #[cfg(feature = "dev-out")]
67 println!(
68 "=> {}: peek: {:?} -> current: {:?}",
69 $message,
70 $self.peek().unwrap_or(&Token::Nil).clone(),
71 $self.get_current().unwrap_or(&Token::Nil)
72 );
73 };
74}
75
76macro_rules! devout {
77 ($($arg:tt)*) => {
78 #[cfg(feature = "dev-out")]
79 println!($($arg)*);
80 }
81 }
82
83macro_rules! op_assign {
84 ($self:ident, $ident:ident,$op:ident) => {{
85 let value = $self.expression();
86 let bin = Expression::Binary {
87 left: Box::new(Expression::Variable {
88 $ident,
89 location: $self.get_last_loc(),
90 }),
91 operator: Operator::$op,
92 right: Box::new(value),
93 location: $self.get_last_loc(),
94 };
95 Expression::Assign {
96 ident: $ident,
97 value: Box::new(bin),
98 location: $self.get_last_loc(),
99 }
100 }};
101}
102
103macro_rules! expect_token {
105 ($self:ident $token:ident) => {{
106 if let Token::$token = $self.peek()? {
107 $self.eat();
108 } else {
109 return Err($self.error_at(SiltError::ExpectedToken(Token::$token)));
110 }
111 };};
112 ($self:ident, $token:ident, $custom_error:expr) => {{
113 if let Token::$token = $self.peek()? {
114 $self.eat();
115 } else {
116 return Err($custom_error);
117 }
118 };};
119}
120macro_rules! expect_token_exp {
121 ($self:ident $token:ident) => {{
122 if let Some(&Token::$token) = $self.peek() {
123 $self.eat();
124 } else {
125 $self.error(SiltError::ExpectedToken(Token::$token));
126 return Expression::InvalidExpression;
127 }
128 };};
129}
130
131macro_rules! rule {
132 ($prefix:expr, $infix:expr, $precedence:tt) => {{
133 ParseRule {
134 prefix: $prefix,
135 infix: $infix,
136 precedence: Precedence::$precedence,
137 }
138 }};
139 () => {};
140}
141
142#[derive(PartialEq, PartialOrd)]
144enum Precedence {
145 None,
146 Assignment, Or, And, Equality, Comparison, Concat, Term, Factor, Unary, Call, Primary,
157}
158type Ident = u8;
161
162type Catch = Result<(), ErrorTuple>;
163
164impl Precedence {
165 fn next(self) -> Self {
166 match self {
167 Precedence::None => Precedence::Assignment,
168 Precedence::Assignment => Precedence::Or,
169 Precedence::Or => Precedence::And,
170 Precedence::And => Precedence::Equality,
171 Precedence::Equality => Precedence::Comparison,
172 Precedence::Comparison => Precedence::Concat,
173 Precedence::Concat => Precedence::Term,
174 Precedence::Term => Precedence::Factor,
175 Precedence::Factor => Precedence::Unary,
176 Precedence::Unary => Precedence::Call,
177 Precedence::Call => Precedence::Primary,
178 Precedence::Primary => Precedence::Primary, }
180 }
181}
182
183impl Display for Precedence {
184 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185 match self {
186 Precedence::None => write!(f, "None"),
187 Precedence::Assignment => write!(f, "Assignment"),
188 Precedence::Or => write!(f, "Or"),
189 Precedence::And => write!(f, "And"),
190 Precedence::Equality => write!(f, "Equality"),
191 Precedence::Comparison => write!(f, "Comparison"),
192 Precedence::Concat => write!(f, "Concat"),
193 Precedence::Term => write!(f, "Term"),
194 Precedence::Factor => write!(f, "Factor"),
195 Precedence::Unary => write!(f, "Unary"),
196 Precedence::Call => write!(f, "Call"),
197 Precedence::Primary => write!(f, "Primary"),
198 }
199 }
200}
201
202struct ParseRule {
203 prefix: fn(&mut Compiler, can_assign: bool) -> Catch,
204 infix: fn(&mut Compiler, can_assign: bool) -> Catch,
205 precedence: Precedence,
206}
207
208struct Local {
210 ident: Option<Box<String>>,
211 depth: usize,
213 functional_depth: usize,
215 is_captured: bool,
216}
217
218struct UpLocal {
219 ident: u8,
221 neighboring: bool,
224 universal_ident: u8,
225}
226
227pub struct Compiler {
228 pub body: FunctionObject,
229 iterator: Peekable<Lexer>,
230 pub current_index: usize,
231 pub errors: Vec<ErrorTuple>,
232 pub valid: bool,
233 current: Result<Token, ErrorTuple>,
234 current_location: Location,
235 scope_depth: usize,
236 functional_depth: usize,
237 up_values: Vec<Vec<UpLocal>>,
239 local_offset: Vec<usize>,
240 local_functional_offset: Vec<usize>,
242 locals: Vec<Local>,
243 local_count: usize,
244 labels: HashMap<String, usize>,
245 pending_gotos: Vec<(String, usize, Location)>,
249 extra: bool, override_pop: bool,
252}
253
254impl<'a> Compiler {
255 pub fn new() -> Compiler {
257 Self {
259 body: FunctionObject::new(None, true),
260 iterator: Lexer::new("".to_string()).peekable(),
261 current: Ok(Token::Nil),
262 current_location: (0, 0),
263 current_index: 0,
264 errors: vec![],
265 valid: true,
266 scope_depth: 0,
267 functional_depth: 0,
268 up_values: vec![vec![]],
269 locals: vec![Local {
270 ident: None,
271 depth: 0,
272 functional_depth: 0,
273 is_captured: false,
274 }],
275 local_functional_offset: vec![],
276 local_offset: vec![],
277 local_count: 1,
278 labels: HashMap::new(),
279 pending_gotos: vec![],
280 extra: true,
284 override_pop: false,
285 }
286 }
287
288 fn error_syntax(&mut self, code: SiltError, location: Location) -> ErrorTuple {
290 self.valid = false;
291 self.body.chunk.invalidate();
292 ErrorTuple { code, location }
293 }
294
295 fn error_at(&mut self, code: SiltError) -> ErrorTuple {
297 self.error_syntax(code, self.current_location)
298 }
299
300 pub fn print_errors(&self) {
302 for e in &self.errors {
303 println!("!!{} at {}:{}", e.code, e.location.0, e.location.1);
304 }
305 }
306
307 pub fn error_string(&self) -> String {
308 let mut s = String::new();
309 for e in &self.errors {
310 s.push_str(&format!(
311 "!!{} at {}:{}",
312 e.code, e.location.0, e.location.1
313 ));
314 }
315 s
316 }
317
318 fn push_error(&mut self, code: ErrorTuple) {
320 self.errors.push(code);
321 }
322
323 pub fn get_errors(&self) -> &Vec<ErrorTuple> {
325 &self.errors
326 }
327
328 pub fn pop_errors(&mut self) -> Vec<ErrorTuple> {
329 std::mem::replace(&mut self.errors, vec![])
330 }
331
332 fn get_chunk(&self) -> &Chunk {
333 &self.body.chunk
334 }
335
336 fn get_chunk_mut(&mut self) -> &mut Chunk {
337 &mut self.body.chunk
338 }
339
340 fn get_chunk_size(&self) -> usize {
341 self.body.chunk.code.len()
342 }
343
344 fn write_code(&mut self, byte: OpCode, location: Location) -> usize {
345 self.body.chunk.write_code(byte, location)
346 }
347
348 fn read_last_code(&self) -> &OpCode {
349 self.body.chunk.read_last_code()
350 }
351
352 fn write_identifier(&mut self, identifier: Box<String>) -> usize {
353 self.body.chunk.write_identifier(identifier)
354 }
355
356 fn pop(&mut self) -> (Result<Token, ErrorTuple>, Location) {
358 self.current_index += 1;
359 match self.iterator.next() {
360 Some(Ok(t)) => {
361 devout!("popped {}", t.0);
362 (Ok(t.0), t.1)
363 }
364 Some(Err(e)) => {
365 let l = e.location;
366 (Err(e), l)
367 }
368 None => (Ok(Token::EOF), (0, 0)),
369 }
370 }
371
372 fn force_stack_pop(&mut self, n: usize) {
374 self.locals.truncate(self.locals.len() - n);
375 self.emit_at(OpCode::POPS(n as u8));
376 }
377
378 fn eat(&mut self) {
380 self.current_index += 1;
381 let t = self.iterator.next();
382 #[cfg(feature = "dev-out")]
383 {
384 match t {
385 Some(Ok(t)) => println!("eat {}", t.0),
386 Some(Err(e)) => println!("eat {}", e.code),
387 None => println!("eat {:?}", Token::EOF),
388 }
389 }
390 }
391
392 fn store(&mut self) {
394 self.current_index += 1;
395 (self.current, self.current_location) = match self.iterator.next() {
396 Some(Ok(t)) => (Ok(t.0), t.1),
397 Some(Err(e)) => {
398 let l = e.location;
400 (Err(e), l)
401 }
402 None => (Ok(Token::EOF), (0, 0)),
403 };
404 }
405
406 fn copy_store(&mut self) -> Result<Token, ErrorTuple> {
408 self.current.clone()
410 }
411
412 fn store_and_return(&mut self) -> Result<Token, ErrorTuple> {
414 self.current_index += 1;
415 let (r, l) = match self.iterator.next() {
416 Some(Ok(t)) => (Ok(t.0), t.1),
417 Some(Err(e)) => {
418 let l = e.location;
420 (Err(e), l)
421 }
422 None => (Ok(Token::EOF), (0, 0)),
423 };
424
425 self.current_location = l;
426 std::mem::replace(&mut self.current, r)
427 }
428
429 fn get_current(&self) -> Result<&Token, ErrorTuple> {
431 match &self.current {
432 Ok(t) => {
433 devout!("get_current {}", t);
434 Ok(t)
435 }
436 Err(e) => Err(e.clone()),
437 }
438 }
439
440 fn peek(&mut self) -> Result<&Token, ErrorTuple> {
448 match self.iterator.peek() {
449 Some(Ok(t)) => {
450 devout!("peek {}", t.0);
451 Ok(&t.0)
452 }
453 Some(Err(e)) => {
454 devout!("peek err {}", e.code);
456 let l = e.location;
457 Err(ErrorTuple {
458 code: e.code.clone(),
459 location: l,
460 })
461 }
462 None => Ok(&Token::EOF),
463 }
464 }
465
466 fn peek_result(&mut self) -> &TokenResult {
468 #[cfg(feature = "dev-out")]
469 match self.iterator.peek() {
470 Some(r) => {
471 match r {
472 Ok(t) => {
473 println!("peek_res {}", t.0);
474 }
475 Err(e) => {
476 println!("peek_res err {}", e.code);
477 }
478 }
479 r
480 }
481 None => &Ok((Token::EOF, (0, 0))),
482 }
483 #[cfg(not(feature = "dev-out"))]
484 match self.iterator.peek() {
485 Some(r) => r,
486 None => &Ok((Token::EOF, (0, 0))),
487 }
488 }
489
490 fn emit(&mut self, op: OpCode, location: Location) {
492 #[cfg(feature = "dev-out")]
493 {
494 println!("emit ... {}", op);
495 }
497 self.write_code(op, location);
498 }
499
500 fn emit_at(&mut self, op: OpCode) {
502 #[cfg(feature = "dev-out")]
503 {
504 println!("emit_at ...{}", op);
505 }
507 self.write_code(op, self.current_location);
508 }
509
510 fn emit_index(&mut self, op: OpCode) -> usize {
512 #[cfg(feature = "dev-out")]
513 {
514 println!("emit_index ... {}", op);
515 }
517 self.write_code(op, self.current_location)
518 }
519
520 fn patch(&mut self, offset: usize) -> Catch {
522 let jump = self.get_chunk().code.len() - offset - 1;
523 if jump > u16::MAX as usize {
524 self.error_at(SiltError::TooManyOperations);
525 }
526 match self.get_chunk().code[offset] {
529 OpCode::GOTO_IF_FALSE(_) => {
530 self.get_chunk_mut().code[offset] = OpCode::GOTO_IF_FALSE(jump as u16)
531 }
532 OpCode::GOTO_IF_TRUE(_) => {
533 self.get_chunk_mut().code[offset] = OpCode::GOTO_IF_TRUE(jump as u16)
534 }
535 OpCode::POP_AND_GOTO_IF_FALSE(_) => {
536 self.get_chunk_mut().code[offset] = OpCode::POP_AND_GOTO_IF_FALSE(jump as u16)
537 }
538 OpCode::FORWARD(_) => self.get_chunk_mut().code[offset] = OpCode::FORWARD(jump as u16),
539 OpCode::REWIND(_) => self.get_chunk_mut().code[offset] = OpCode::REWIND(jump as u16),
540 OpCode::FOR_NUMERIC(_) => {
541 self.get_chunk_mut().code[offset] = OpCode::FOR_NUMERIC(jump as u16)
542 }
543 _ => {
544 return Err(self.error_at(SiltError::ChunkCorrupt));
545 }
546 }
547 Ok(())
548 }
549
550 fn emit_rewind(&mut self, start: usize) {
551 let jump = (self.get_chunk_size() + 1) - start;
553 if jump > u16::MAX as usize {
554 self.error_at(SiltError::TooManyOperations);
555 }
556 self.write_code(OpCode::REWIND(jump as u16), self.current_location);
557 }
558
559 fn set_label(&mut self, label: String) {
560 self.labels.insert(label, self.get_chunk_size());
561 }
562
563 fn identifer_constant(&mut self, ident: Box<String>) -> u8 {
564 self.write_identifier(ident) as u8
565 }
566
567 fn write_constant(&mut self, value: Value) -> u8 {
569 self.body.chunk.write_constant(value) as u8
570 }
571
572 fn constant(&mut self, value: Value, location: Location) {
574 let constant = self.write_constant(value);
575 self.emit(OpCode::CONSTANT { constant }, location);
576 }
577
578 fn constant_at(&mut self, value: Value) {
580 self.constant(value, self.current_location);
581 }
582
583 fn emit_identifer_constant_at(&mut self, ident: Box<String>) {
585 let constant = self.write_identifier(ident) as u8;
586 self.emit(OpCode::CONSTANT { constant }, self.current_location);
587 }
588
589 fn is_end(&mut self) -> bool {
590 match self.iterator.peek() {
591 None => true,
592 _ => false,
593 }
594 }
595
596 fn swap_function(&mut self, mut func: &mut FunctionObject) {
598 swap(&mut self.body, func);
599 }
601
602 fn get_rule(token: &Token) -> ParseRule {
603 match token {
614 Token::OpenParen => rule!(grouping, call, Call),
615 Token::OpenBrace => rule!(tabulate, call_table, None),
616 Token::Assign => rule!(void, void, None),
617 Token::Op(op) => match op {
618 Operator::Sub => rule!(unary, binary, Term),
619 Operator::Add => rule!(void, binary, Term),
620 Operator::Multiply => rule!(void, binary, Factor),
621 Operator::Divide => rule!(void, binary, Factor),
622 Operator::Not => rule!(unary, void, None),
623 Operator::NotEqual => rule!(void, binary, Equality),
624 Operator::Equal => rule!(void, binary, Equality),
625 Operator::Less => rule!(void, binary, Comparison),
626 Operator::LessEqual => rule!(void, binary, Comparison),
627 Operator::Greater => rule!(void, binary, Comparison),
628 Operator::GreaterEqual => rule!(void, binary, Comparison),
629 Operator::Concat => rule!(void, concat, Concat),
630 Operator::And => rule!(void, and, And),
631 Operator::Or => rule!(void, or, Or),
632 Operator::Length => rule!(unary, void, None),
633 _ => rule!(void, void, None),
634 },
635 Token::Identifier(_) => rule!(variable, void, None),
636 Token::Integer(_) => rule!(integer, void, None),
638 Token::Number(_) => rule!(number, void, None),
639 Token::StringLiteral(_) => rule!(string, call_string, None),
640 Token::Nil => rule!(literal, void, None),
641 Token::True => rule!(literal, void, None),
642 Token::False => rule!(literal, void, None),
643 _ => rule!(void, void, None),
645 }
646 }
647
648 pub fn compile(&mut self, source: String) -> FunctionObject {
649 #[cfg(feature = "dev-out")]
650 {
651 let lexer = Lexer::new(source.to_owned());
652 lexer.for_each(|r| match r {
653 Ok(t) => {
654 println!("token {}", t.0);
655 }
656 Err(e) => println!("err {}", e),
657 });
658 }
659 let lexer = Lexer::new(source.to_owned());
660 self.iterator = lexer.peekable();
661 while !self.is_end() {
662 match declaration(self) {
663 Ok(()) => {}
664 Err(e) => {
665 self.push_error(e);
666 self.synchronize();
667 }
668 }
669 }
670
671 self.emit(OpCode::RETURN, (0, 0));
672 take(&mut self.body)
673 }
674
675 fn synchronize(&mut self) {
676 }
686
687 fn parse_precedence(&mut self, precedence: Precedence, skip_step: bool) -> Catch {
688 if !skip_step {
689 self.store();
690 }
691 let t = self.get_current()?;
694 let loc = self.current_location;
695
696 devout!("check rule for token {}", t);
697 let rule = Self::get_rule(&t);
698 devout!(
700 "target precedence: {}, current precedence: {}",
701 precedence,
702 rule.precedence,
703 );
704 let can_assign = precedence <= Precedence::Assignment;
706 (rule.prefix)(self, can_assign)?;
707
708 loop {
709 let c = self.peek_result();
710 let rule = match c {
711 Ok((Token::EOF, _)) => break,
712 Ok((t, _)) => Self::get_rule(t),
713 Err(e) => {
714 return Err(e.clone());
715 }
716 };
717 devout!(
718 "loop target precedence for : {}, current precedence for : {}",
719 precedence,
720 rule.precedence
721 );
722 if precedence > rule.precedence {
723 break;
724 }
725 self.store();
726 (rule.infix)(self, false)?;
727 }
728
729 if can_assign
731 && if let Token::Assign = self.peek()? {
732 true
733 } else {
734 false
735 }
736 {
737 let res = self.peek()?.clone();
738 return Err(self.error_at(SiltError::InvalidAssignment(res)));
739 }
740
741 Ok(())
745 }
746}
747
748fn declaration(this: &mut Compiler) -> Catch {
749 devout!("----------------------------");
750 devnote!(this "declaration");
751
752 let t = this.peek()?;
753 match t {
754 Token::Local => declaration_keyword(this, true, false)?,
755 Token::Global => declaration_keyword(this, false, false)?,
756 Token::Function => {
757 this.eat();
758 define_function(this, true, None)?;
759 }
760 _ => statement(this)?,
761 }
762 Ok(())
763}
764
765fn declaration_keyword(this: &mut Compiler, local: bool, already_function: bool) -> Catch {
766 devnote!(this "declaration_keyword");
767 this.eat();
768 let (res, location) = this.pop();
769 match res? {
770 Token::Identifier(ident) => {
771 if this.scope_depth > 0 && local {
772 add_local(this, ident)?;
775 typing(this, None)?;
776 } else {
777 let ident = this.identifer_constant(ident); typing(this, Some((ident, location)))?;
779 }
780 }
781 Token::Function => {
782 if !already_function {
783 define_function(this, local, None)?;
784 } else {
785 return Err(this.error_at(SiltError::ExpectedLocalIdentifier));
786 }
788 }
789 _ => todo!(),
794 }
795 Ok(())
796}
797
798fn declaration_scope(
799 this: &mut Compiler,
800 ident: Box<String>,
801 local: bool,
802 location: Location,
803) -> Catch {
804 if this.scope_depth > 0 && local {
805 add_local(this, ident)?;
808 typing(this, None)?;
809 } else {
810 let ident = this.identifer_constant(ident);
811 typing(this, Some((ident, location)))?;
812 }
813 Ok(())
814}
815
816fn add_local(this: &mut Compiler, ident: Box<String>) -> Result<u8, ErrorTuple> {
833 _add_local(this, Some(ident))
834}
835
836fn add_local_placeholder(this: &mut Compiler) -> Result<u8, ErrorTuple> {
838 _add_local(this, None)
839}
840
841fn _add_local(this: &mut Compiler, ident: Option<Box<String>>) -> Result<u8, ErrorTuple> {
842 devnote!(this "add_local");
843 let i = this.local_count; if i == 255 {
850 return Err(this.error_at(SiltError::TooManyLocals));
851 }
852 this.locals.push(Local {
853 ident,
854 depth: this.scope_depth,
855 functional_depth: this.functional_depth,
856 is_captured: false,
857 });
858 this.local_count += 1;
859 Ok(i as u8)
865}
866
867fn resolve_local(this: &mut Compiler, ident: &Box<String>) -> Option<(u8, bool)> {
875 devnote!(this "resolve_local");
876 for (i, l) in this.locals.iter_mut().enumerate().rev() {
877 if let Some(local_ident) = &l.ident {
878 if local_ident == ident {
879 #[cfg(feature = "dev-out")]
880 println!("matched local {}->{} at {}", ident, local_ident, i);
881 let ident_byte = i as u8;
882
883 let is_upvalue = l.functional_depth < this.functional_depth;
885 return if is_upvalue {
886 (*l).is_captured = true;
887 let offset_ident = if l.functional_depth > 0 {
888 let offset = this.local_functional_offset[l.functional_depth - 1];
889 i - offset
890 } else {
891 i
892 } as u8;
893 Some((
895 resolve_upvalue(
896 &mut this.up_values,
897 ident_byte,
898 offset_ident,
899 this.functional_depth,
900 l.functional_depth,
901 ),
902 is_upvalue,
903 ))
904 } else {
905 let offset_ident = if this.functional_depth > 0 {
906 let offset = this.local_functional_offset[this.functional_depth - 1];
907 i - offset
908 } else {
909 i
910 } as u8;
911 Some((offset_ident as u8, false))
912 };
913 }
914 }
915 }
916 None
917}
918
919fn resolve_upvalue(
921 up_values: &mut Vec<Vec<UpLocal>>,
922 ident: u8,
923 scoped_ident: u8,
924 level: usize,
925 target: usize,
926) -> u8 {
927 let m = &mut up_values[level];
928 for (u, i) in m.iter().enumerate() {
929 if i.universal_ident == ident {
930 return u as u8;
931 }
932 }
933 if level <= target + 1 {
935 m.push(UpLocal {
936 ident: scoped_ident,
937 universal_ident: ident,
938 neighboring: true,
939 });
940 (m.len() - 1) as u8
941 } else {
942 let higher = resolve_upvalue(up_values, ident, scoped_ident, level - 1, target);
944 let m = &mut up_values[level];
945 m.push(UpLocal {
946 ident: higher,
947 universal_ident: ident,
948 neighboring: false,
949 });
950 (m.len() - 1) as u8
951 }
953}
954
955fn typing(this: &mut Compiler, ident_tuple: Option<(Ident, Location)>) -> Catch {
970 devnote!(this "typing");
971 if let Token::Colon = this.peek()? {
972 this.eat();
974 this.store();
975 let t = this.get_current()?;
976 if let Token::ColonIdentifier(target) = t {
977 define_declaration(this, ident_tuple)?;
988 } else {
989 todo!("typing");
990 }
993 } else {
994 define_declaration(this, ident_tuple)?;
995 }
996 Ok(())
997}
998
999fn define_declaration(this: &mut Compiler, ident_tuple: Option<(Ident, Location)>) -> Catch {
1000 devnote!(this "define_declaration");
1001 this.store();
1002 let t = this.get_current()?;
1003 match t {
1004 Token::Assign => {
1005 expression(this, false)?;
1006 }
1007 Token::AddAssign
1009 | Token::SubAssign
1010 | Token::MultiplyAssign
1011 | Token::DivideAssign
1012 | Token::ModulusAssign => {
1013 todo!()
1017 }
1018 _ => this.emit_at(OpCode::NIL), }
1020 define_variable(this, ident_tuple)?;
1021 Ok(())
1022}
1023
1024fn define_variable(this: &mut Compiler, ident: Option<(Ident, Location)>) -> Catch {
1025 devnote!(this "define_variable");
1026
1027 if let Some(ident) = ident {
1028 this.emit(OpCode::DEFINE_GLOBAL { constant: ident.0 }, ident.1);
1029 }
1030 Ok(())
1031}
1032
1033fn define_function(this: &mut Compiler, local: bool, pre_ident: Option<usize>) -> Catch {
1034 let (ident, location) = if let &Token::Identifier(_) = this.peek()? {
1035 let (res, location) = this.pop();
1036 if let Token::Identifier(ident) = res? {
1037 (ident, location)
1038 } else {
1039 unreachable!()
1040 }
1041 } else {
1042 (Box::new("anonymous".to_string()), this.current_location)
1043 };
1044
1045 let ident_clone = *ident.clone();
1046 let global_ident = if this.scope_depth > 0 && local {
1047 add_local(this, ident)?;
1050 None
1051 } else {
1052 let ident = Some((this.identifer_constant(ident), location));
1053 ident
1054 };
1055
1056 build_function(this, ident_clone, global_ident, false, false)?;
1057
1058 Ok(())
1059}
1060
1061fn build_function(
1063 this: &mut Compiler,
1064 ident: String,
1065 global_ident: Option<(u8, Location)>,
1066 is_script: bool,
1067 implicit_return: bool,
1068) -> Catch {
1069 devnote!(this "build_function");
1071 let mut sidelined_func = FunctionObject::new(Some(ident), is_script);
1072 this.swap_function(&mut sidelined_func);
1073 begin_scope(this);
1074 begin_functional_scope(this);
1075 expect_token!(this OpenParen);
1076 let mut arity = 0;
1077 if let Token::Identifier(_) = this.peek()? {
1078 arity += 1;
1079 build_param(this)?;
1080
1081 while let Token::Comma = this.peek()? {
1082 this.eat();
1083 arity += 1;
1084 if arity > 255 {
1085 return Err(this.error_at(SiltError::TooManyParameters));
1087 }
1088 build_param(this)?;
1089 }
1090 }
1091
1092 block(this)?;
1093 if let &OpCode::RETURN = this.read_last_code() {
1094 } else {
1095 if !implicit_return {
1097 this.emit_at(OpCode::NIL);
1098 }
1099 this.emit_at(OpCode::RETURN);
1100 }
1101
1102 end_scope(this, true);
1108 let upvals = end_functional_scope(this);
1109 this.swap_function(&mut sidelined_func);
1111 sidelined_func.upvalue_count = upvals.len() as u8;
1112 let func_value = Value::Function(Rc::new(sidelined_func));
1113 if true {
1114 let constant = this.body.chunk.write_constant(func_value) as u8;
1116 this.emit_at(OpCode::CLOSURE { constant });
1117 for val in upvals.iter() {
1120 this.emit_at(OpCode::REGISTER_UPVALUE {
1122 index: val.ident,
1123 neighboring: val.neighboring,
1124 });
1125 }
1126 } else {
1127 this.constant_at(func_value);
1129 }
1130 define_variable(this, global_ident)?;
1131
1132 Ok(())
1133}
1134
1135fn build_param(this: &mut Compiler) -> Catch {
1136 let (res, _) = this.pop();
1137 match res? {
1138 Token::Identifier(ident) => {
1139 add_local(this, ident)?;
1140 }
1141 _ => {
1142 return Err(this.error_at(SiltError::ExpectedLocalIdentifier));
1143 }
1144 }
1145 Ok(())
1146}
1147
1148fn statement(this: &mut Compiler) -> Catch {
1149 devnote!(this "statement");
1150 match this.peek()? {
1151 Token::Print => print(this)?,
1152 Token::If => if_statement(this)?,
1153 Token::Do => {
1154 this.eat();
1155 begin_scope(this);
1156 block(this)?;
1157 end_scope(this, false);
1158 }
1159 Token::While => while_statement(this)?,
1160 Token::For => for_statement(this)?,
1161 Token::Return => return_statement(this)?,
1162 Token::ColonColon => set_goto_label(this)?,
1164 Token::Goto => goto_statement(this)?,
1165 Token::SemiColon => {
1166 this.eat();
1167 }
1169 _ => expression_statement(this)?,
1174 }
1175 Ok(())
1176}
1177
1178fn block(this: &mut Compiler) -> Catch {
1179 devnote!(this "block");
1180 build_block_until_then_eat!(this, End);
1181
1182 Ok(())
1183}
1184
1185fn begin_scope(this: &mut Compiler) {
1187 this.scope_depth += 1;
1188}
1189
1190fn begin_functional_scope(this: &mut Compiler) {
1192 this.functional_depth += 1;
1193 this.up_values.push(vec![]);
1194 let cumulative: usize = this.local_functional_offset.iter().sum();
1195 this.local_functional_offset
1196 .push(this.local_count + cumulative - 1);
1197 this.local_offset.push(this.local_count);
1198 this.local_count = 1;
1199}
1200
1201fn end_scope(this: &mut Compiler, skip_code: bool) {
1203 this.scope_depth -= 1;
1204
1205 let mut last_was_pop = true;
1206 let mut count = 0;
1207 let mut v = vec![];
1208 while !this.locals.is_empty() && this.locals.last().unwrap().depth > this.scope_depth {
1209 let l = this.locals.pop().unwrap();
1210 this.local_count -= 1;
1211 if l.is_captured {
1212 if last_was_pop {
1213 v.push(count);
1214 count = 0;
1215 }
1216 last_was_pop = false;
1217 count += 1;
1218 } else {
1219 if !last_was_pop {
1220 v.push(count);
1221 count = 0;
1222 }
1223 last_was_pop = true;
1224 count += 1;
1225 }
1226 }
1227 if count > 0 {
1228 v.push(count);
1229 }
1230 if skip_code {
1232 return;
1234 }
1235
1236 v.iter().enumerate().for_each(|(i, c)| {
1238 if i % 2 == 0 {
1239 this.emit_at(OpCode::POPS(*c));
1240 } else {
1241 this.emit_at(OpCode::CLOSE_UPVALUES(*c));
1242 }
1243 });
1244}
1245
1246fn end_functional_scope(this: &mut Compiler) -> Vec<UpLocal> {
1248 this.functional_depth -= 1;
1249 this.local_functional_offset.pop();
1250 this.local_count = match this.local_offset.pop() {
1251 Some(v) => v,
1252 None => 1,
1253 };
1254
1255 this.up_values.pop().unwrap()
1256}
1257
1258fn if_statement(this: &mut Compiler) -> Catch {
1259 devnote!(this "if_statement");
1260 this.eat();
1261 expression(this, false)?;
1262 expect_token!(this Then);
1263 let skip_if = this.emit_index(OpCode::POP_AND_GOTO_IF_FALSE(0));
1264 scope_and_block_until!(this, End | Else | ElseIf);
1265 match this.peek()? {
1267 Token::Else => {
1268 this.eat();
1269 let skip_else = this.emit_index(OpCode::FORWARD(0));
1270 this.patch(skip_if)?; scope_and_block_until!(this, End);
1272 this.patch(skip_else)?;
1273 expect_token!(this End);
1274 }
1275 Token::ElseIf => {
1276 this.eat();
1277 this.patch(skip_if)?;
1279 if_statement(this)?;
1280 }
1281 _ => {
1282 this.patch(skip_if)?;
1283 }
1284 }
1285 Ok(())
1286}
1287
1288fn while_statement(this: &mut Compiler) -> Catch {
1289 devnote!(this "while_statement");
1290 this.eat();
1291 let loop_start = this.get_chunk_size();
1292 expression(this, false)?;
1293 expect_token!(this Do);
1294 let exit_jump = this.emit_index(OpCode::POP_AND_GOTO_IF_FALSE(0));
1295 build_block_until_then_eat!(this, End);
1296 this.emit_rewind(loop_start);
1297 this.patch(exit_jump)?;
1298 Ok(())
1299}
1300
1301fn for_statement(this: &mut Compiler) -> Catch {
1308 devnote!(this "for_statement");
1309 this.eat();
1310 let pair = this.pop();
1311 let t = pair.0?;
1312 if let Token::Identifier(ident) = t {
1313 let iterator = add_local_placeholder(this)?; expect_token!(this Assign);
1316 add_local_placeholder(this)?; add_local_placeholder(this)?; expression(this, false)?; expect_token!(this Comma);
1320 expression(this, false)?; if let Token::Comma = this.peek()? {
1326 this.eat();
1327 expression(this, false)?;
1328 } else {
1329 this.constant_at(Value::Integer(1))
1330 };
1331 let for_start = this.emit_index(OpCode::FOR_NUMERIC(0));
1332 expect_token!(this Do);
1340 begin_scope(this);
1341 add_local(this, ident)?; build_block_until_then_eat!(this, End);
1343 end_scope(this, false);
1344
1345 this.emit_at(OpCode::INCREMENT { index: iterator });
1346 this.emit_rewind(for_start);
1347 this.patch(for_start)?;
1348 this.force_stack_pop(3);
1349 Ok(())
1350 } else {
1351 Err(this.error_at(SiltError::ExpectedLocalIdentifier))
1352 }
1353}
1354
1355fn generic_for_statement() {}
1360
1361fn return_statement(this: &mut Compiler) -> Catch {
1362 devnote!(this "return_statement");
1363 this.eat();
1364 if let Token::End | Token::Else | Token::ElseIf | Token::SemiColon | Token::EOF = this.peek()? {
1365 this.emit_at(OpCode::NIL);
1366 } else {
1367 expression(this, false)?;
1368 }
1369 this.emit_at(OpCode::RETURN);
1370 Ok(())
1371}
1372
1373fn set_goto_label(this: &mut Compiler) -> Catch {
1374 devnote!(this "goto_label");
1375 this.eat();
1376 let token = this.pop().0?;
1377 if let Token::Identifier(ident) = token {
1378 this.labels.insert(*ident, this.get_chunk_size());
1379 } else {
1380 return Err(this.error_at(SiltError::ExpectedLabelIdentifier));
1381 }
1382 Ok(())
1383}
1384
1385fn goto_statement(this: &mut Compiler) -> Catch {
1386 devnote!(this "goto_statement");
1387 this.eat();
1388 let token = this.pop().0?;
1389 if let Token::Identifier(ident) = token {
1390 resolve_goto(this, &*ident, this.get_chunk_size(), None)?;
1391 } else {
1416 return Err(this.error_at(SiltError::ExpectedGotoIdentifier));
1417 }
1418
1419 Ok(())
1430}
1431
1432fn resolve_goto(
1433 this: &mut Compiler,
1434 ident: &str,
1435 op_count: usize,
1436 replace: Option<(usize, Location)>,
1437) -> Catch {
1438 match this.labels.get(ident) {
1439 Some(i) => {
1440 let c = op_count;
1441 let o = *i;
1442 let code = if c > o {
1443 let offset = c - o;
1444 if offset > u16::MAX as usize {
1445 return Err(this.error_at(SiltError::TooManyOperations));
1446 }
1447 OpCode::REWIND(offset as u16)
1448 } else {
1449 let offset = o - c;
1450 if offset > u16::MAX as usize {
1451 return Err(this.error_at(SiltError::TooManyOperations));
1452 }
1453 OpCode::FORWARD(offset as u16)
1454 };
1455
1456 match replace {
1457 Some((i, _)) => {
1458 this.get_chunk_mut().code[i] = code;
1459 }
1460 None => {
1461 this.emit_at(code);
1462 }
1463 }
1464 }
1465 None => match replace {
1466 Some((i, location)) => {
1467 return Err(this.error_syntax(SiltError::UndefinedLabel(ident.to_owned()), location))
1468 }
1469 None => {
1470 let index = this.emit_index(OpCode::FORWARD(0));
1471 this.pending_gotos
1472 .push((ident.to_owned(), index, this.current_location));
1473 } },
1475 };
1476 Ok(())
1477}
1478
1479fn final_resolve_goto(this: &mut Compiler) {
1480 this.pending_gotos
1481 .iter()
1482 .for_each(|(ident, index, location)| {});
1483}
1484
1485fn goto_scope_skip(this: &mut Compiler) {
1486 if this.locals.is_empty() {
1487 return;
1488 }
1489 let mut i = 0;
1490 this.locals
1491 .iter()
1492 .rev()
1493 .take_while(|l| l.depth > this.scope_depth)
1494 .for_each(|_| {
1495 i += 1;
1496 });
1497
1498 this.emit_at(OpCode::POPS(i));
1499}
1500
1501fn expression(this: &mut Compiler, skip_step: bool) -> Catch {
1502 devnote!(this "expression");
1503 this.parse_precedence(Precedence::Assignment, skip_step)?;
1504 Ok(())
1505}
1506
1507fn next_expression(this: &mut Compiler) -> Catch {
1508 devnote!(this "next_expression");
1509 this.eat();
1510 expression(this, false)?;
1511 Ok(())
1512}
1513
1514fn expression_statement(this: &mut Compiler) -> Catch {
1515 devnote!(this "expression_statement");
1516 expression(this, false)?;
1517 if this.override_pop {
1518 this.override_pop = false;
1519 } else {
1520 this.emit_at(OpCode::POP);
1521 }
1522 devnote!(this "expression_statement end");
1523 Ok(())
1524}
1525
1526fn variable(this: &mut Compiler, can_assign: bool) -> Catch {
1527 devnote!(this "variable");
1528 named_variable(this, can_assign, false)?;
1543 Ok(())
1544}
1545
1546fn named_variable(this: &mut Compiler, can_assign: bool, mut local: bool) -> Catch {
1547 devnote!(this "named_variables");
1548 let t = this.copy_store()?;
1549
1550 if this.scope_depth > 0
1553 && if let Token::Op(Operator::ColonEquals) = this.peek()? {
1554 true
1555 } else {
1556 false
1557 }
1558 {
1559 if let Token::Identifier(ident) = t {
1560 add_local(this, ident)?;
1562 this.override_pop = true;
1563 this.eat();
1564 expression(this, false)?;
1565 } else {
1566 unreachable!()
1567 }
1568 return Ok(());
1569 }
1570
1571 let (setter, getter) = if let Token::Identifier(ident) = t {
1573 devout!("assigning to identifier: {}", ident);
1574 match resolve_local(this, &ident) {
1576 Some((i, is_up)) => {
1577 if is_up {
1578 (
1579 OpCode::SET_UPVALUE { index: i },
1580 OpCode::GET_UPVALUE { index: i },
1581 )
1582 } else {
1583 (
1584 OpCode::SET_LOCAL { index: i },
1585 OpCode::GET_LOCAL { index: i },
1586 )
1587 }
1588 }
1589 None => {
1590 let ident = this.identifer_constant(ident);
1591 (
1593 OpCode::SET_GLOBAL { constant: ident },
1594 OpCode::GET_GLOBAL { constant: ident },
1595 )
1596 }
1597 }
1598 } else {
1599 unreachable!()
1600 };
1601
1602 devout!("setter: {}, getter: {}", setter, getter);
1603
1604 match this.peek()? {
1619 Token::Assign => {
1620 if can_assign {
1621 this.eat();
1622 expression(this, false)?;
1623 this.emit_at(setter);
1624 } else {
1625 this.emit_at(getter);
1626 }
1627 }
1628 Token::OpenBracket | Token::Dot => {
1629 this.emit_at(getter);
1630 let count = table_indexer(this)? as u8;
1631 if let Token::Assign = this.peek()? {
1632 this.eat();
1633 expression(this, false)?;
1634 this.emit_at(OpCode::TABLE_SET { depth: count });
1635 this.override_pop = true;
1637 } else {
1638 this.emit_at(OpCode::TABLE_GET { depth: count });
1639 }
1640 }
1641 _ => this.emit_at(getter),
1642 }
1643
1644 Ok(())
1666}
1667
1668fn grouping(this: &mut Compiler, _can_assign: bool) -> Catch {
1669 devnote!(this "grouping");
1670 expression(this, false)?;
1671 Ok(())
1675}
1676
1677fn tabulate(this: &mut Compiler, _can_assign: bool) -> Catch {
1678 devnote!(this "tabulate");
1679 this.emit_at(OpCode::NEW_TABLE);
1680 if !matches!(this.peek()?, &Token::CloseBrace) {
1682 let mut count = 0;
1683 while {
1685 let start_brace = this.current_location;
1686 if match this.peek()? {
1687 Token::Identifier(_) => {
1688 this.store();
1689 if let Token::Assign = this.peek()? {
1690 let ident = this.get_current()?.unwrap_identifier();
1691 this.emit_identifer_constant_at(ident.clone());
1692 this.eat();
1693 true
1694 } else {
1695 expression(this, true)?; false
1697 }
1698 }
1699 Token::OpenBracket => {
1700 this.eat();
1701 expression(this, false)?;
1702 expect_token!(
1703 this,
1704 CloseBracket,
1705 this.error_at(SiltError::UnterminatedBracket(start_brace.0, start_brace.1))
1706 );
1707 expect_token!(this, Assign, this.error_at(SiltError::ExpectedAssign));
1708 true
1709 }
1710 _ => {
1711 expression(this, false)?; false
1713 }
1714 } {
1715 expression(this, false)?;
1716 this.emit_at(OpCode::TABLE_INSERT { offset: count });
1717 } else {
1718 count += 1;
1719 }
1720
1721 match this.peek()? {
1722 Token::Comma => {
1723 this.eat();
1724 true
1725 }
1726 Token::CloseBrace => false,
1727 _ => return Err(this.error_at(SiltError::TableExpectedCommaOrCloseBrace)),
1728 }
1729 } {
1730 }
1734 if count > 0 {
1735 this.emit_at(OpCode::TABLE_BUILD(count));
1736 }
1737 }
1738
1739 expect_token!(
1740 this,
1741 CloseBrace,
1742 this.error_at(SiltError::TableExpectedCommaOrCloseBrace)
1743 );
1744 Ok(())
1745}
1746
1747fn unary(this: &mut Compiler, _can_assign: bool) -> Catch {
1749 devnote!(this "unary");
1750 let t = this.copy_store()?;
1751 this.parse_precedence(Precedence::Unary, false)?;
1754 match t {
1755 Token::Op(Operator::Sub) => this.emit_at(OpCode::NEGATE),
1756 Token::Op(Operator::Not) => this.emit_at(OpCode::NOT),
1757 Token::Op(Operator::Length) => this.emit_at(OpCode::LENGTH),
1758 _ => {}
1759 }
1760 Ok(())
1772}
1773
1774fn table_indexer(this: &mut Compiler) -> Result<usize, ErrorTuple> {
1775 let mut count = 0;
1776 while match this.peek()? {
1777 Token::OpenBracket => {
1778 this.eat();
1779 expression(this, false)?;
1780 expect_token!(
1781 this,
1782 CloseBracket,
1783 this.error_at(SiltError::UnterminatedBracket(0, 0))
1784 );
1785 true
1786 }
1787 Token::Dot => {
1788 this.eat();
1789 let t = this.pop();
1790 this.current_location = t.1;
1791 let field = t.0?;
1792 devout!("table_indexer: {} p:{}", field, this.peek()?);
1793 if let Token::Identifier(ident) = field {
1794 this.emit_identifer_constant_at(ident);
1795 } else {
1796 return Err(this.error_at(SiltError::ExpectedFieldIdentifier));
1797 }
1798 true
1799 }
1800 _ => false,
1801 } {
1802 count += 1;
1803 }
1804 Ok(count)
1805}
1806
1807fn binary(this: &mut Compiler, _can_assign: bool) -> Catch {
1808 devnote!(this "binary");
1809 let t = this.copy_store()?;
1810 let l = this.current_location;
1811 let rule = Compiler::get_rule(&t);
1812 this.parse_precedence(rule.precedence.next(), false)?;
1813 if let Token::Op(op) = t {
1814 match op {
1815 Operator::Add => this.emit(OpCode::ADD, l),
1816 Operator::Sub => this.emit(OpCode::SUB, l),
1817 Operator::Multiply => this.emit(OpCode::MULTIPLY, l),
1818 Operator::Divide => this.emit(OpCode::DIVIDE, l),
1819
1820 Operator::Concat => this.emit(OpCode::CONCAT, l),
1821
1822 Operator::Equal => this.emit(OpCode::EQUAL, l),
1825 Operator::NotEqual => this.emit(OpCode::NOT_EQUAL, l),
1826 Operator::Less => this.emit(OpCode::LESS, l),
1827 Operator::LessEqual => this.emit(OpCode::LESS_EQUAL, l),
1828 Operator::Greater => this.emit(OpCode::GREATER, l),
1829 Operator::GreaterEqual => this.emit(OpCode::GREATER_EQUAL, l),
1830
1831 _ => todo!(),
1832 }
1833 }
1834 Ok(())
1835}
1836
1837fn concat(this: &mut Compiler, _can_assign: bool) -> Catch {
1838 devnote!(this "concat_binary");
1839 let t = this.copy_store()?;
1840 let l = this.current_location;
1841 let rule = Compiler::get_rule(&t);
1842 this.parse_precedence(rule.precedence.next(), false)?;
1843
1844 if let Token::Op(op) = t {
1845 match op {
1846 Operator::Concat => this.emit(OpCode::CONCAT, l),
1847 _ => todo!(),
1848 }
1849 }
1850 Ok(())
1851}
1852
1853fn and(this: &mut Compiler, _can_assign: bool) -> Catch {
1854 devnote!(this "and");
1855 let index = this.emit_index(OpCode::GOTO_IF_FALSE(0));
1856 this.emit_at(OpCode::POP);
1857 this.parse_precedence(Precedence::And, false)?;
1858 this.patch(index)?;
1859 Ok(())
1860}
1861
1862fn or(this: &mut Compiler, _can_assign: bool) -> Catch {
1863 devnote!(this "or");
1864
1865 let index = this.emit_index(OpCode::GOTO_IF_TRUE(0));
1874 this.emit_at(OpCode::POP);
1875 this.parse_precedence(Precedence::Or, false)?;
1876 this.patch(index)?;
1877 Ok(())
1878}
1879
1880fn integer(this: &mut Compiler, can_assign: bool) -> Catch {
1881 devnote!(this "integer");
1882 let t = this.copy_store()?;
1883 let value = if let Token::Integer(i) = t {
1884 Value::Integer(i)
1885 } else {
1886 unreachable!()
1887 };
1888 this.constant_at(value);
1889 Ok(())
1890}
1891
1892fn number(this: &mut Compiler, can_assign: bool) -> Catch {
1893 devnote!(this "number");
1894 let t = this.copy_store()?;
1895 let value = if let Token::Number(n) = t {
1896 Value::Number(n)
1897 } else {
1898 unreachable!()
1899 };
1900 this.constant_at(value);
1901 Ok(())
1902}
1903
1904fn string(this: &mut Compiler, can_assign: bool) -> Catch {
1905 devnote!(this "string");
1906 let t = this.copy_store()?;
1907 let value = if let Token::StringLiteral(s) = t {
1908 Value::String(Box::new(s.into_string()))
1909 } else {
1910 unreachable!()
1911 };
1912 this.constant_at(value);
1913 Ok(())
1914}
1915
1916fn literal(this: &mut Compiler, can_assign: bool) -> Catch {
1917 devnote!(this "literal");
1918 let t = this.copy_store()?;
1919 match t {
1920 Token::Nil => this.emit_at(OpCode::NIL),
1921 Token::True => this.emit_at(OpCode::TRUE),
1922 Token::False => this.emit_at(OpCode::FALSE),
1923 _ => unreachable!(),
1924 }
1925 Ok(())
1926}
1927
1928fn call(this: &mut Compiler, can_assign: bool) -> Catch {
1929 devnote!(this "call");
1930 let start = this.current_location;
1939 let arg_count = arguments(this, start)?;
1940 this.emit(OpCode::CALL(arg_count), start);
1941 Ok(())
1942}
1943
1944fn call_table(this: &mut Compiler, can_assign: bool) -> Catch {
1945 todo!();
1946 Ok(())
1947}
1948
1949fn call_string(this: &mut Compiler, can_assign: bool) -> Catch {
1950 todo!();
1951 Ok(())
1952}
1953fn arguments(this: &mut Compiler, start: Location) -> Result<u8, ErrorTuple> {
1954 devnote!(this "arguments");
1955 let mut args = 0;
1956 if !matches!(this.peek()?, &Token::CloseParen) {
1957 while {
1958 expression(this, false)?;
1959 args += 1;
1960 if let &Token::Comma = this.peek()? {
1961 this.eat();
1962 true
1963 } else {
1964 false
1965 }
1966 } {
1967 if args >= 255 {
1968 return Err(this.error_at(SiltError::TooManyParameters));
1969 }
1970 }
1971 }
1972
1973 expect_token!(
1974 this,
1975 CloseParen,
1976 this.error_at(SiltError::UnterminatedParenthesis(start.0, start.1))
1977 );
1978 devout!("arguments count: {}", args);
1979
1980 Ok(args)
1981}
1982
1983fn print(this: &mut Compiler) -> Catch {
1984 devnote!(this "print");
1985 this.eat();
1986 expression(this, false)?;
1987 this.emit_at(OpCode::PRINT);
1988 Ok(())
1989}
1990
1991pub fn void(_this: &mut Compiler, _can_assign: bool) -> Catch {
1992 devnote!(_this "void");
1993 Ok(())
1994}
1995
1996