|
1 | 1 | use chumsky::span::SimpleSpan; |
| 2 | +use std::collections::HashMap; |
2 | 3 |
|
3 | 4 | use crate::vm::chunk::Chunk; |
4 | 5 | use crate::vm::instruction::Instruction; |
@@ -559,6 +560,54 @@ impl Compiler { |
559 | 560 | Expr::Import { name, alias } => { |
560 | 561 | self.emit(Instruction::Import { path: name.clone(), alias: alias.clone() }, span); |
561 | 562 | } |
| 563 | + |
| 564 | + Expr::Class { name, methods } => { |
| 565 | + let mut methods_map = HashMap::new(); |
| 566 | + |
| 567 | + for f in methods { |
| 568 | + if let Expr::Function { name: method_name, args, body } = &f.node { |
| 569 | + let chunk_id = self.chunks.len() + self.offset; |
| 570 | + self.chunks.push(Chunk::new(&format!("{}::{}", name, method_name))); |
| 571 | + |
| 572 | + let saved_chunk = self.current_chunk; |
| 573 | + self.current_chunk = chunk_id; |
| 574 | + |
| 575 | + let saved_scope = self.scope.enter_function(); |
| 576 | + self.scope.define_local("self"); |
| 577 | + |
| 578 | + for arg in args { |
| 579 | + self.scope.define_local(arg); |
| 580 | + } |
| 581 | + |
| 582 | + self.compile_expr(*body.clone())?; |
| 583 | + |
| 584 | + if method_name == "new" { |
| 585 | + self.emit(Instruction::LoadLocal(0), span); |
| 586 | + } else { |
| 587 | + self.emit(Instruction::PushNull, span); |
| 588 | + } |
| 589 | + |
| 590 | + self.emit(Instruction::Return, span); |
| 591 | + |
| 592 | + let locals_count = self.scope.exit_function(saved_scope); |
| 593 | + self.chunks[chunk_id].locals_count = locals_count; |
| 594 | + self.current_chunk = saved_chunk; |
| 595 | + |
| 596 | + methods_map.insert( |
| 597 | + method_name.clone(), |
| 598 | + Value::Function { chunk_id, arity: args.len() } |
| 599 | + ); |
| 600 | + } else { |
| 601 | + return Err("class body can only contain functions".to_string()); |
| 602 | + } |
| 603 | + } |
| 604 | + |
| 605 | + let class_value = Value::Class { name: name.clone(), methods: methods_map }; |
| 606 | + let index = self.add_constant(class_value); |
| 607 | + |
| 608 | + self.emit(Instruction::Push(index), span); |
| 609 | + self.store_variable(name, span); |
| 610 | + } |
562 | 611 | } |
563 | 612 |
|
564 | 613 | Ok(()) |
|
0 commit comments