1use compiler::symbol_table::{Symbol, SymbolScope, SymbolTable};
7use object::builtins::BuiltIns;
8use parser::ast::{
9 BlockStatement, ClassDeclaration, Expression, FunctionDeclaration, Let, Literal,
10 MethodDefinition, MethodKind, Node, Statement,
11};
12use parser::lexer::token::{Span, TokenKind};
13use parser::validation::validate_program;
14use std::rc::Rc;
15
16use crate::emitter::{
17 call_area_size, scratch_area_size, slot_offset, AsmDialect, Assembly, Emitter, FunctionFrame,
18 CLOSURE_SLOT_OFFSET,
19};
20use crate::runtime_core::{
21 builtin_id_for_symbol_index, builtin_value, i64_fits_smi, FALSE_VALUE, NULL_VALUE, TRUE_VALUE,
22};
23
24pub const MAX_FUNCTION_PARAMETERS: usize = 7;
27pub const MAX_METHOD_PARAMETERS: usize = 6;
28
29fn main_epilogue_label(dialect: AsmDialect) -> String {
32 format!("{}main_exit", dialect.local_label_prefix())
33}
34
35#[derive(Clone, Debug)]
36pub struct LowerError {
37 pub message: String,
38 pub span: Option<(usize, usize)>,
39}
40
41impl std::fmt::Display for LowerError {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 write!(f, "{}", self.message)
44 }
45}
46
47fn error<T>(message: impl Into<String>, span: &Span) -> Result<T, LowerError> {
48 Err(LowerError {
49 message: message.into(),
50 span: Some((span.start, span.end)),
51 })
52}
53
54pub fn lower_node(
59 source: &str,
60 node: &Node,
61 dialect: AsmDialect,
62 observe: bool,
63) -> Result<Assembly, LowerError> {
64 let program = match node {
65 Node::Program(program) => program,
66 _ => {
67 return Err(LowerError {
68 message: "lowering expects a full program".to_string(),
69 span: None,
70 })
71 }
72 };
73 let builtin_names: Vec<&str> = BuiltIns.iter().map(|builtin| builtin.name).collect();
74 validate_program(program, &builtin_names).map_err(|validation| LowerError {
75 message: validation.message,
76 span: Some((validation.span.start, validation.span.end)),
77 })?;
78
79 let mut symbols = SymbolTable::new();
80 for (index, builtin) in BuiltIns.iter().enumerate() {
81 symbols.define_builtin(index, builtin.name.to_string());
82 }
83
84 let exit_label = main_epilogue_label(dialect);
85 let mut lowerer = Lowerer {
86 source,
87 emitter: Emitter::new(dialect),
88 symbols,
89 epilogues: vec![exit_label.clone()],
90 };
91
92 let mut last_leaves_value = false;
93 for statement in &program.body {
94 last_leaves_value = lowerer.lower_statement(statement)?;
95 }
96 if !last_leaves_value {
97 lowerer.emitter.without_span(|emitter| {
100 emitter.load_imm64("x0", NULL_VALUE, "program result: null");
101 });
102 }
103
104 let globals_count = lowerer.symbols.num_definitions;
105 Ok(lowerer.emitter.finish(globals_count, &exit_label, observe))
106}
107
108pub fn compile_source(
111 source: &str,
112 dialect: AsmDialect,
113 observe: bool,
114) -> Result<Assembly, String> {
115 let node = parser::parse(source).map_err(|errors| errors.join("\n"))?;
116 lower_node(source, &node, dialect, observe).map_err(|lower| lower.message)
117}
118
119struct Lowerer<'a> {
120 source: &'a str,
121 emitter: Emitter,
122 symbols: SymbolTable,
123 epilogues: Vec<String>,
126}
127
128impl<'a> Lowerer<'a> {
129 fn snippet(&self, span: &Span) -> String {
130 let text = self.source.get(span.start..span.end).unwrap_or("");
131 let mut cleaned: String = text
132 .chars()
133 .take(40)
134 .map(|c| if c == '\n' || c == '\r' || c == '\t' { ' ' } else { c })
135 .collect();
136 if text.chars().count() > 40 {
137 cleaned.push('…');
138 }
139 cleaned
140 }
141
142 fn enter_scope(&mut self) {
143 let outer = std::mem::replace(&mut self.symbols, SymbolTable::new());
144 self.symbols = SymbolTable::new_enclosed_symbol_table(outer);
145 }
146
147 fn leave_scope(&mut self) {
148 let outer = self
149 .symbols
150 .outer
151 .as_ref()
152 .expect("leave_scope at the global scope")
153 .as_ref()
154 .clone();
155 self.symbols = outer;
156 }
157
158 fn lower_statement(&mut self, statement: &Statement) -> Result<bool, LowerError> {
162 match statement {
163 Statement::Let(let_statement) => {
164 self.lower_let(let_statement)?;
165 Ok(false)
166 }
167 Statement::Return(return_statement) => {
168 let comment = format!("return {}", self.snippet(return_statement.argument.span()));
169 let target = self
170 .epilogues
171 .last()
172 .expect("epilogue stack is never empty")
173 .clone();
174 self.emitter.comment(&comment);
175 self.lower_expression(&return_statement.argument)?;
176 let span = return_statement.span.clone();
177 self.emitter.with_span(&span, |emitter| {
178 emitter.ins(&format!("b {}", target));
179 });
180 Ok(true)
181 }
182 Statement::Expr(expression) => {
183 self.lower_expression(expression)?;
184 Ok(true)
185 }
186 Statement::Class(class) => {
187 self.lower_class(class)?;
188 Ok(false)
189 }
190 Statement::SetProperty(set) => {
191 let comment = self.snippet(&set.span);
192 self.emitter.comment(&comment);
193 self.lower_expression(&set.object)?;
194 self.emitter.with_span(&set.span.clone(), |emitter| {
195 emitter.push_acc("object");
196 });
197 self.lower_expression(&set.value)?;
198 let (name_label, name_len) =
199 self.emitter.intern_string(set.property.name.as_bytes());
200 let property = set.property.name.clone();
201 self.emitter.with_span(&set.span.clone(), |emitter| {
202 emitter.ins_cmt("mov x3, x0", "value");
203 emitter.pop("x0", "object");
204 emitter.load_label_address("x1", &name_label, &property);
205 emitter.load_imm64("x2", name_len, "");
206 emitter.call_runtime("rt_set_property", "");
207 });
208 Ok(false)
209 }
210 }
211 }
212
213 fn lower_let(&mut self, let_statement: &Let) -> Result<(), LowerError> {
214 let name = let_statement.identifier.kind.to_string();
215 let comment = self.snippet(&let_statement.span);
216 self.emitter.comment(&comment);
217 self.lower_expression(&let_statement.expr)?;
221 let symbol = self.symbols.define(name.clone());
222 let span = let_statement.span.clone();
223 self.emitter.with_span(&span, |emitter| match symbol.scope {
224 SymbolScope::Global => {
225 emitter.global_store("x0", symbol.index, &format!("let {}", name))
226 }
227 _ => emitter.frame_store("x0", slot_offset(symbol.index), &format!("let {}", name)),
228 });
229 Ok(())
230 }
231
232 fn lower_block_value(&mut self, block: &BlockStatement) -> Result<(), LowerError> {
235 let mut leaves_value = false;
236 for statement in &block.body {
237 leaves_value = self.lower_statement(statement)?;
238 }
239 if !leaves_value {
240 self.emitter.without_span(|emitter| {
241 emitter.load_imm64("x0", NULL_VALUE, "empty/valueless block: null");
242 });
243 }
244 Ok(())
245 }
246
247 fn load_symbol(&mut self, symbol: &Rc<Symbol>, span: &Span) -> Result<(), LowerError> {
248 let name = symbol.name.clone();
249 match symbol.scope {
250 SymbolScope::Global => {
251 let index = symbol.index;
252 self.emitter.with_span(&span.clone(), |emitter| {
253 emitter.global_load("x0", index, &name);
254 });
255 }
256 SymbolScope::LOCAL => {
257 let index = symbol.index;
258 self.emitter.with_span(&span.clone(), |emitter| {
259 emitter.frame_load("x0", slot_offset(index), &name);
260 });
261 }
262 SymbolScope::Builtin => {
263 let id = match builtin_id_for_symbol_index(symbol.index) {
264 Some(id) => id,
265 None => return error(format!("unknown builtin '{}'", name), span),
266 };
267 self.emitter.with_span(&span.clone(), |emitter| {
268 emitter.load_imm64("x0", builtin_value(id), &format!("builtin {}", name));
269 });
270 }
271 SymbolScope::Free => {
272 let index = symbol.index;
273 self.emitter.with_span(&span.clone(), |emitter| {
274 emitter.frame_load("x0", CLOSURE_SLOT_OFFSET, "current closure");
275 emitter.load_imm64("x1", index as u64, &format!("free variable {}", name));
276 emitter.call_runtime("rt_get_free", "");
277 });
278 }
279 SymbolScope::Function => {
280 self.emitter.with_span(&span.clone(), |emitter| {
283 emitter.frame_load(
284 "x0",
285 CLOSURE_SLOT_OFFSET,
286 &format!("current closure ({})", name),
287 );
288 });
289 }
290 }
291 Ok(())
292 }
293
294 fn lower_expression(&mut self, expression: &Expression) -> Result<(), LowerError> {
295 match expression {
296 Expression::IDENTIFIER(identifier) => {
297 let symbol = match self.symbols.resolve(identifier.name.clone()) {
298 Some(symbol) => symbol,
299 None => {
300 return error(
301 format!("undefined variable '{}'", identifier.name),
302 &identifier.span,
303 )
304 }
305 };
306 self.load_symbol(&symbol, &identifier.span)
307 }
308 Expression::LITERAL(literal) => self.lower_literal(literal),
309 Expression::PREFIX(prefix) => {
310 self.lower_expression(&prefix.operand)?;
311 let comment = self.snippet(&prefix.span);
312 let runtime_call = match prefix.op.kind {
313 TokenKind::MINUS => "rt_minus",
314 TokenKind::BANG => "rt_bang",
315 _ => {
316 return error(format!("unexpected prefix op: {}", prefix.op), &prefix.span)
317 }
318 };
319 self.emitter.with_span(&prefix.span.clone(), |emitter| {
320 emitter.call_runtime(runtime_call, &comment);
321 });
322 Ok(())
323 }
324 Expression::INFIX(infix) => self.lower_infix(infix),
325 Expression::IF(if_node) => {
326 self.lower_expression(&if_node.condition)?;
327 let else_label = self.emitter.new_label();
328 let end_label = self.emitter.new_label();
329 let comment = format!("if ({})", self.snippet(if_node.condition.span()));
330 self.emitter.with_span(&if_node.span.clone(), |emitter| {
331 emitter.call_runtime("rt_truthy", &comment);
332 emitter.ins(&format!("cbz x0, {}", else_label));
333 });
334 self.lower_block_value(&if_node.consequent)?;
335 self.emitter.with_span(&if_node.span.clone(), |emitter| {
336 emitter.ins(&format!("b {}", end_label));
337 emitter.label(&else_label);
338 });
339 match &if_node.alternate {
340 Some(alternate) => self.lower_block_value(alternate)?,
341 None => {
342 self.emitter.without_span(|emitter| {
343 emitter.load_imm64("x0", NULL_VALUE, "if without else: null");
344 });
345 }
346 }
347 self.emitter.with_span(&if_node.span.clone(), |emitter| {
348 emitter.label(&end_label);
349 });
350 Ok(())
351 }
352 Expression::Index(index) => {
353 self.lower_expression(&index.object)?;
354 self.emitter.with_span(&index.span.clone(), |emitter| {
355 emitter.push_acc("indexed object");
356 });
357 self.lower_expression(&index.index)?;
358 let comment = self.snippet(&index.span);
359 self.emitter.with_span(&index.span.clone(), |emitter| {
360 emitter.ins_cmt("mov x1, x0", "index");
361 emitter.pop("x0", "object");
362 emitter.call_runtime("rt_index", &comment);
363 });
364 Ok(())
365 }
366 Expression::FUNCTION(function) => self.lower_function(function),
367 Expression::FunctionCall(call) => {
368 let argc = call.arguments.len();
369 let area = call_area_size(argc);
370 let comment = self.snippet(&call.span);
371 self.emitter.with_span(&call.span.clone(), |emitter| {
372 emitter.comment(&comment);
373 emitter.sp_sub(area);
374 });
375 self.lower_expression(&call.callee)?;
376 self.emitter.with_span(&call.span.clone(), |emitter| {
377 emitter.sp_store("x0", 0, "callee");
378 });
379 for (index, argument) in call.arguments.iter().enumerate() {
380 self.lower_expression(argument)?;
381 self.emitter.with_span(&call.span.clone(), |emitter| {
382 emitter.sp_store("x0", 8 * (index as u64 + 1), &format!("arg {}", index));
383 });
384 }
385 self.emitter.with_span(&call.span.clone(), |emitter| {
386 emitter.ins_cmt("ldr x0, [sp]", "callee");
387 emitter.load_imm64("x1", argc as u64, "argc");
388 emitter.sp_address("x2", 8, "argv");
389 emitter.call_runtime("rt_call", "");
390 emitter.sp_add(area);
391 });
392 Ok(())
393 }
394 Expression::This(this) => {
395 let symbol = match self.symbols.resolve("this".to_string()) {
396 Some(symbol) => symbol,
397 None => return error("this is only available inside a method", &this.span),
398 };
399 self.load_symbol(&symbol, &this.span)
400 }
401 Expression::Property(property) => {
402 self.lower_expression(&property.object)?;
403 let (name_label, name_len) = self
404 .emitter
405 .intern_string(property.property.name.as_bytes());
406 let name = property.property.name.clone();
407 self.emitter.with_span(&property.span.clone(), |emitter| {
408 emitter.load_label_address("x1", &name_label, &name);
409 emitter.load_imm64("x2", name_len, "");
410 emitter.call_runtime("rt_get_property", &format!(".{}", name));
411 });
412 Ok(())
413 }
414 Expression::New(new_expression) => {
415 let symbol = match self.symbols.resolve(new_expression.callee.name.clone()) {
416 Some(symbol) => symbol,
417 None => {
418 return error(
419 format!("undefined variable '{}'", new_expression.callee.name),
420 &new_expression.callee.span,
421 )
422 }
423 };
424 let argc = new_expression.arguments.len();
425 let area = call_area_size(argc);
426 let comment = self.snippet(&new_expression.span);
427 self.emitter
428 .with_span(&new_expression.span.clone(), |emitter| {
429 emitter.comment(&comment);
430 emitter.sp_sub(area);
431 });
432 self.load_symbol(&symbol, &new_expression.callee.span)?;
433 self.emitter
434 .with_span(&new_expression.span.clone(), |emitter| {
435 emitter.sp_store("x0", 0, "class");
436 });
437 for (index, argument) in new_expression.arguments.iter().enumerate() {
438 self.lower_expression(argument)?;
439 self.emitter
440 .with_span(&new_expression.span.clone(), |emitter| {
441 emitter.sp_store(
442 "x0",
443 8 * (index as u64 + 1),
444 &format!("arg {}", index),
445 );
446 });
447 }
448 self.emitter
451 .with_span(&new_expression.span.clone(), |emitter| {
452 emitter.ins_cmt("ldr x0, [sp]", "class");
453 emitter.load_imm64("x1", argc as u64, "argc");
454 emitter.sp_address("x2", 8, "argv");
455 emitter.call_runtime("rt_construct", "");
456 emitter.sp_add(area);
457 });
458 Ok(())
459 }
460 }
461 }
462
463 fn lower_literal(&mut self, literal: &Literal) -> Result<(), LowerError> {
464 match literal {
465 Literal::Integer(integer) => {
466 let raw = integer.raw;
467 self.emitter.with_span(&integer.span.clone(), |emitter| {
468 if i64_fits_smi(raw) {
469 emitter.load_imm64("x0", (raw << 1) as u64, &format!("{}", raw));
470 } else {
471 emitter.load_imm64("x0", raw as u64, &format!("{} (beyond SMI)", raw));
472 emitter.call_runtime("rt_box_int", "");
473 }
474 });
475 Ok(())
476 }
477 Literal::Boolean(boolean) => {
478 let (value, text) =
479 if boolean.raw { (TRUE_VALUE, "true") } else { (FALSE_VALUE, "false") };
480 self.emitter.with_span(&boolean.span.clone(), |emitter| {
481 emitter.load_imm64("x0", value, text);
482 });
483 Ok(())
484 }
485 Literal::String(string) => {
486 let (label, len) = self.emitter.intern_string(string.raw.as_bytes());
487 let preview = self.snippet(&string.span);
488 self.emitter.with_span(&string.span.clone(), |emitter| {
489 emitter.load_label_address("x0", &label, &preview);
490 emitter.load_imm64("x1", len, "byte length");
491 emitter.call_runtime("rt_string_from_bytes", "");
492 });
493 Ok(())
494 }
495 Literal::Array(array) => {
496 let len = array.elements.len();
497 let area = scratch_area_size(len);
498 self.emitter.with_span(&array.span.clone(), |emitter| {
499 emitter.sp_sub(area);
500 });
501 for (index, element) in array.elements.iter().enumerate() {
502 self.lower_expression(element)?;
503 self.emitter.with_span(&array.span.clone(), |emitter| {
504 emitter.sp_store("x0", 8 * index as u64, &format!("element {}", index));
505 });
506 }
507 self.emitter.with_span(&array.span.clone(), |emitter| {
508 emitter.sp_address("x0", 0, "element base");
509 emitter.load_imm64("x1", len as u64, "element count");
510 emitter.call_runtime("rt_array", "");
511 emitter.sp_add(area);
512 });
513 Ok(())
514 }
515 Literal::Hash(hash) => {
516 let pairs = hash.elements.len();
517 let area = scratch_area_size(pairs * 2);
518 self.emitter.with_span(&hash.span.clone(), |emitter| {
519 emitter.sp_sub(area);
520 });
521 for (index, (key, value)) in hash.elements.iter().enumerate() {
522 self.lower_expression(key)?;
523 self.emitter.with_span(&hash.span.clone(), |emitter| {
524 emitter.sp_store("x0", 8 * (2 * index as u64), &format!("key {}", index));
525 });
526 self.lower_expression(value)?;
527 self.emitter.with_span(&hash.span.clone(), |emitter| {
528 emitter.sp_store(
529 "x0",
530 8 * (2 * index as u64 + 1),
531 &format!("value {}", index),
532 );
533 });
534 }
535 self.emitter.with_span(&hash.span.clone(), |emitter| {
536 emitter.sp_address("x0", 0, "pair base");
537 emitter.load_imm64("x1", pairs as u64, "pair count");
538 emitter.call_runtime("rt_hash", "");
539 emitter.sp_add(area);
540 });
541 Ok(())
542 }
543 }
544 }
545
546 fn lower_infix(&mut self, infix: &parser::ast::BinaryExpression) -> Result<(), LowerError> {
547 let comment = self.snippet(&infix.span);
548 self.lower_expression(&infix.left)?;
549 self.emitter.with_span(&infix.span.clone(), |emitter| {
550 emitter.push_acc("left operand");
551 });
552 self.lower_expression(&infix.right)?;
553
554 if infix.op.kind == TokenKind::LT {
557 self.emitter.with_span(&infix.span.clone(), |emitter| {
558 emitter.pop("x1", "left operand");
559 emitter.call_runtime("rt_gt", &comment);
560 });
561 return Ok(());
562 }
563
564 let runtime_call = match infix.op.kind {
565 TokenKind::PLUS => "rt_add",
566 TokenKind::MINUS => "rt_sub",
567 TokenKind::ASTERISK => "rt_mul",
568 TokenKind::SLASH => "rt_div",
569 TokenKind::GT => "rt_gt",
570 TokenKind::EQ => "rt_eq",
571 TokenKind::NotEq => "rt_neq",
572 _ => return error(format!("unexpected infix op: {}", infix.op), &infix.span),
573 };
574
575 if infix.op.kind == TokenKind::PLUS {
576 let slow_label = self.emitter.new_label();
580 let done_label = self.emitter.new_label();
581 self.emitter.with_span(&infix.span.clone(), |emitter| {
582 emitter.ins_cmt("mov x1, x0", "right operand");
583 emitter.pop("x0", "left operand");
584 emitter.ins_cmt("orr x8, x0, x1", "SMI check on both bit0");
585 emitter.ins(&format!("tbnz x8, #0, {}", slow_label));
586 emitter.ins_cmt("adds x8, x0, x1", "(a<<1)+(b<<1) = (a+b)<<1");
587 emitter.ins(&format!("bvs {}", slow_label));
588 emitter.ins("mov x0, x8");
589 emitter.ins(&format!("b {}", done_label));
590 emitter.label(&slow_label);
591 emitter.call_runtime(runtime_call, &comment);
592 emitter.label(&done_label);
593 });
594 return Ok(());
595 }
596
597 self.emitter.with_span(&infix.span.clone(), |emitter| {
598 emitter.ins_cmt("mov x1, x0", "right operand");
599 emitter.pop("x0", "left operand");
600 emitter.call_runtime(runtime_call, &comment);
601 });
602 Ok(())
603 }
604
605 fn lower_function(&mut self, function: &FunctionDeclaration) -> Result<(), LowerError> {
606 if function.params.len() > MAX_FUNCTION_PARAMETERS {
607 return error(
608 format!("functions accept at most {} parameters", MAX_FUNCTION_PARAMETERS),
609 &function.span,
610 );
611 }
612 self.enter_scope();
613 if !function.name.is_empty() {
616 self.symbols.define_function_name(function.name.clone());
617 }
618 let mut parameter_names = Vec::with_capacity(function.params.len());
619 for parameter in &function.params {
620 self.symbols.define(parameter.name.clone());
621 parameter_names.push(parameter.name.clone());
622 }
623
624 let label = self.emitter.new_function_label();
625 let epilogue_label = format!("{}_ret", label);
626 let display_name = if function.name.is_empty() {
627 "fn".to_string()
628 } else {
629 format!("fn {}", function.name)
630 };
631 let signature = format!("{}({})", display_name, parameter_names.join(", "));
632
633 self.epilogues.push(epilogue_label.clone());
634 self.emitter.begin_function();
635 self.lower_block_value(&function.body)?;
636 self.epilogues.pop();
637
638 let num_definitions = self.symbols.num_definitions;
639 let free_symbols = self.symbols.free_symbols.clone();
640 self.emitter.end_function(FunctionFrame {
641 label: label.clone(),
642 comment: signature.clone(),
643 num_parameters: function.params.len(),
644 num_definitions,
645 epilogue_label,
646 parameter_names,
647 });
648 self.leave_scope();
649
650 self.emit_closure(&label, function.params.len(), &free_symbols, &signature, &function.span)
651 }
652
653 fn lower_method(
654 &mut self,
655 class_name: &str,
656 method: &MethodDefinition,
657 ) -> Result<(), LowerError> {
658 if method.params.len() > MAX_METHOD_PARAMETERS {
659 return error(
660 format!("methods accept at most {} parameters", MAX_METHOD_PARAMETERS),
661 &method.span,
662 );
663 }
664 self.enter_scope();
665 self.symbols.define("this".to_string());
668 let mut parameter_names = vec!["this".to_string()];
669 for parameter in &method.params {
670 self.symbols.define(parameter.name.clone());
671 parameter_names.push(parameter.name.clone());
672 }
673
674 let label = self.emitter.new_function_label();
675 let epilogue_label = format!("{}_ret", label);
676 let signature =
677 format!("{}.{}({})", class_name, method.name.name, parameter_names.join(", "));
678
679 self.epilogues.push(epilogue_label.clone());
680 self.emitter.begin_function();
681 self.lower_block_value(&method.body)?;
682 if method.kind == MethodKind::Constructor {
683 self.emitter.without_span(|emitter| {
686 emitter.frame_load("x0", slot_offset(0), "constructor returns this");
687 });
688 }
689 self.epilogues.pop();
690
691 let num_definitions = self.symbols.num_definitions;
692 let free_symbols = self.symbols.free_symbols.clone();
693 self.emitter.end_function(FunctionFrame {
694 label: label.clone(),
695 comment: signature.clone(),
696 num_parameters: method.params.len() + 1,
697 num_definitions,
698 epilogue_label,
699 parameter_names,
700 });
701 self.leave_scope();
702
703 self.emit_closure(&label, method.params.len() + 1, &free_symbols, &signature, &method.span)
704 }
705
706 fn emit_closure(
710 &mut self,
711 code_label: &str,
712 num_parameters: usize,
713 free_symbols: &[Rc<Symbol>],
714 signature: &str,
715 span: &Span,
716 ) -> Result<(), LowerError> {
717 let num_free = free_symbols.len();
718 let area = scratch_area_size(num_free);
719 self.emitter.with_span(&span.clone(), |emitter| {
720 emitter.sp_sub(area);
721 });
722 for (index, symbol) in free_symbols.iter().enumerate() {
723 self.load_symbol(symbol, span)?;
724 let name = symbol.name.clone();
725 self.emitter.with_span(&span.clone(), |emitter| {
726 emitter.sp_store("x0", 8 * index as u64, &format!("capture {}", name));
727 });
728 }
729 self.emitter.with_span(&span.clone(), |emitter| {
730 emitter.load_label_address("x0", code_label, signature);
731 emitter.load_imm64("x1", num_parameters as u64, "num_parameters");
732 emitter.sp_address("x2", 0, "captured values");
733 emitter.load_imm64("x3", num_free as u64, "num_free");
734 emitter.call_runtime("rt_closure", "");
735 emitter.sp_add(area);
736 });
737 Ok(())
738 }
739
740 fn lower_class(&mut self, class: &ClassDeclaration) -> Result<(), LowerError> {
741 let class_name = class.name.name.clone();
742 let comment = format!("class {}", class_name);
743 self.emitter.comment(&comment);
744 let symbol = self.symbols.define(class_name.clone());
747 let (name_label, name_len) = self.emitter.intern_string(class_name.as_bytes());
748 self.emitter.with_span(&class.span.clone(), |emitter| {
749 emitter.load_label_address("x0", &name_label, &class_name);
750 emitter.load_imm64("x1", name_len, "");
751 emitter.call_runtime("rt_class", "");
752 emitter.push_acc("class value");
753 });
754 for method in &class.methods {
755 self.lower_method(&class_name, method)?;
756 let (method_label, method_len) =
757 self.emitter.intern_string(method.name.name.as_bytes());
758 let is_constructor = method.kind == MethodKind::Constructor;
759 let method_name = method.name.name.clone();
760 self.emitter.with_span(&method.span.clone(), |emitter| {
761 emitter.ins_cmt("mov x3, x0", "method closure");
762 emitter.ins_cmt("ldr x0, [sp]", "class value (kept pushed)");
763 emitter.load_label_address("x1", &method_label, &method_name);
764 emitter.load_imm64("x2", method_len, "");
765 emitter.load_imm64("x4", if is_constructor { 1 } else { 0 }, "is_ctor");
766 emitter.call_runtime("rt_class_add_method", "");
767 });
768 }
769 self.emitter.with_span(&class.span.clone(), |emitter| {
770 emitter.pop("x0", "class value");
771 });
772 let span = class.span.clone();
773 self.emitter.with_span(&span, |emitter| match symbol.scope {
774 SymbolScope::Global => {
775 emitter.global_store("x0", symbol.index, &format!("class {}", class_name))
776 }
777 _ => emitter.frame_store(
778 "x0",
779 slot_offset(symbol.index),
780 &format!("class {}", class_name),
781 ),
782 });
783 Ok(())
784 }
785}