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