1use crate::CodegenBackend;
2use ling_ast::ast::BinOp;
3use ling_ast::ast::UnOp;
4use ling_mir::ir::*;
5use std::collections::HashMap;
6
7const OP_NOP: u8 = 0;
10const OP_PUSHI64: u8 = 1;
11const OP_PUSHF64: u8 = 2;
12const OP_PUSHSTR: u8 = 3;
13const OP_PUSHBOOL: u8 = 4;
14const OP_PUSHNONE: u8 = 5;
15const OP_POP: u8 = 6;
16const OP_LOADLOCAL: u8 = 7;
17const OP_STORELOCAL: u8 = 8;
18const OP_ADD: u8 = 9;
19const OP_SUB: u8 = 10;
20const OP_MUL: u8 = 11;
21const OP_DIV: u8 = 12;
22const OP_REM: u8 = 13;
23const OP_EQ: u8 = 14;
24const OP_NE: u8 = 15;
25const OP_LT: u8 = 16;
26const OP_LE: u8 = 17;
27const OP_GT: u8 = 18;
28const OP_GE: u8 = 19;
29const OP_AND: u8 = 20;
30const OP_OR: u8 = 21;
31const OP_NOT: u8 = 22;
32const OP_NEG: u8 = 23;
33const OP_CALL: u8 = 24;
34const OP_CALLBUILTIN: u8 = 25;
35const OP_RET: u8 = 26;
36const OP_JUMP: u8 = 27;
37const OP_JUMPIFFALSE: u8 = 28;
38const OP_MAKELIST: u8 = 29;
39const OP_GETINDEX: u8 = 30;
40const OP_HALT: u8 = 0xFF;
41
42#[derive(Debug, Clone)]
45pub enum Value {
46 Number(f64),
47 Bool(bool),
48 Str(String),
49 None,
50 List(Vec<Value>),
51}
52
53impl Value {
54 fn is_truthy(&self) -> bool {
55 match self {
56 Value::Bool(b) => *b,
57 Value::Number(n) => *n != 0.0,
58 Value::Str(s) => !s.is_empty(),
59 Value::List(l) => !l.is_empty(),
60 Value::None => false,
61 }
62 }
63
64 fn display(&self) -> String {
65 match self {
66 Value::Number(n) => {
67 if n.fract() == 0.0 && n.is_finite() && n.abs() < 1e15 {
68 format!("{:.0}", n)
69 } else {
70 format!("{}", n)
71 }
72 },
73 Value::Bool(b) => b.to_string(),
74 Value::Str(s) => s.clone(),
75 Value::None => "()".to_string(),
76 Value::List(l) => {
77 let items: Vec<String> = l.iter().map(|v| v.display()).collect();
78 format!("[{}]", items.join(", "))
79 },
80 }
81 }
82}
83
84fn values_equal(a: &Value, b: &Value) -> bool {
85 match (a, b) {
86 (Value::Number(a), Value::Number(b)) => a.to_bits() == b.to_bits(),
87 (Value::Bool(a), Value::Bool(b)) => a == b,
88 (Value::Str(a), Value::Str(b)) => a == b,
89 (Value::None, Value::None) => true,
90 (Value::List(a), Value::List(b)) => {
91 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| values_equal(x, y))
92 },
93 _ => false,
94 }
95}
96
97fn num_cmp<F: Fn(f64, f64) -> bool>(a: &Value, b: &Value, cmp: F) -> bool {
98 match (a, b) {
99 (Value::Number(a), Value::Number(b)) => cmp(*a, *b),
100 _ => false,
101 }
102}
103
104fn resolve_builtin(name: &str) -> Result<(&'static str, usize), String> {
105 match name {
106 "print" | "println" | "พิมพ์" | "印" | "打印" | "印刷" => Ok(("print", 1)),
107 "format" | "รูปแบบ" | "格式" | "フォーマット" | "서식" => {
108 Ok(("format", 0))
109 },
110 "len" | "str_len" | "ความยาว" | "长度" | "長さ" | "길이" => {
111 Ok(("len", 1))
112 },
113 "to_str" | "str" | "แปลงสตริง" => Ok(("to_str", 1)),
114 "sin" => Ok(("sin", 1)),
115 "cos" => Ok(("cos", 1)),
116 _ => Err(format!("unknown builtin: {}", name)),
117 }
118}
119
120#[derive(Debug, Default)]
123pub struct Chunk {
124 pub code: Vec<u8>,
125 pub floats: Vec<f64>,
126 pub strings: Vec<String>,
127 pub local_count: u16,
128}
129
130impl Chunk {
131 fn w(&mut self, b: u8) {
132 self.code.push(b);
133 }
134 fn w2(&mut self, v: u16) {
135 self.code.extend_from_slice(&v.to_le_bytes());
136 }
137 fn w8(&mut self, v: i64) {
138 self.code.extend_from_slice(&v.to_le_bytes());
139 }
140 fn add_float(&mut self, v: f64) -> u16 {
141 let i = self.floats.len();
142 self.floats.push(v);
143 i as u16
144 }
145 fn add_str(&mut self, s: &str) -> u16 {
146 let i = self.strings.len();
147 self.strings.push(s.to_string());
148 i as u16
149 }
150}
151
152#[derive(Debug)]
155pub struct CompiledFunction {
156 pub name: String,
157 pub chunk: Chunk,
158 pub arg_count: u16,
159}
160
161#[derive(Debug)]
162pub struct VmProgram {
163 pub functions: Vec<CompiledFunction>,
164 pub main_index: usize,
165}
166
167struct Ctx {
170 chunk: Chunk,
171 local_map: HashMap<Local, u16>,
172 local_next: u16,
173 bb_start: HashMap<usize, usize>,
174 patches: Vec<(usize, usize)>,
175}
176
177pub fn compile_mir_program(mir: &MirProgram) -> VmProgram {
178 let fn_names: Vec<String> = mir.functions.iter().map(|f| f.name.clone()).collect();
179 let mut functions = Vec::new();
180 let mut main_index = 0;
181
182 for (i, mir_fn) in mir.functions.iter().enumerate() {
183 let chunk = compile_fn(mir_fn, &fn_names);
184 if mir_fn.name == "__main__" || mir_fn.name == "start" || mir_fn.name == "เริ่ม" {
185 main_index = i;
186 }
187 functions.push(CompiledFunction {
188 name: mir_fn.name.clone(),
189 chunk,
190 arg_count: mir_fn.arg_count as u16,
191 });
192 }
193
194 if functions.is_empty() {
195 functions.push(CompiledFunction {
196 name: "__main__".into(),
197 chunk: Chunk { code: vec![OP_PUSHNONE, OP_RET], ..Default::default() },
198 arg_count: 0,
199 });
200 }
201
202 VmProgram { functions, main_index }
203}
204
205fn compile_fn(mir_fn: &MirFunction, fn_names: &[String]) -> Chunk {
206 let mut ctx = Ctx {
207 chunk: Chunk::default(),
208 local_map: HashMap::new(),
209 local_next: 0,
210 bb_start: HashMap::new(),
211 patches: Vec::new(),
212 };
213
214 ctx.local_map.insert(Local(0), 0);
216
217 for i in 0..mir_fn.arg_count {
219 let local = Local(i + 1);
220 ctx.local_map.entry(local).or_insert_with(|| {
221 let s = ctx.local_next;
222 ctx.local_next += 1;
223 s
224 });
225 }
226
227 for li in 0..mir_fn.locals.len() {
229 let local = Local(mir_fn.arg_count + 1 + li);
230 ctx.local_map.entry(local).or_insert_with(|| {
231 let s = ctx.local_next;
232 ctx.local_next += 1;
233 s
234 });
235 }
236
237 ctx.chunk.local_count = ctx.local_next;
238
239 for bb_idx in 0..mir_fn.basic_blocks.len() {
240 ctx.bb_start.insert(bb_idx, ctx.chunk.code.len());
241 let bb = &mir_fn.basic_blocks[bb_idx];
242 for stmt in &bb.statements {
243 compile_stmt(stmt, fn_names, &mut ctx);
244 }
245 if let Some(term) = &bb.terminator {
246 compile_term(term, fn_names, &mut ctx);
247 }
248 }
249
250 for &(pos, target) in &ctx.patches {
251 let target_offset = ctx.bb_start.get(&target).copied().unwrap_or(0);
252 ctx.chunk.code[pos..pos + 2].copy_from_slice(&(target_offset as u16).to_le_bytes());
253 }
254
255 ctx.chunk
256}
257
258fn compile_stmt(stmt: &Statement, fn_names: &[String], ctx: &mut Ctx) {
259 match &stmt.kind {
260 StatementKind::Assign(local, rvalue) => {
261 compile_rval(rvalue, fn_names, ctx);
262 let slot = *ctx.local_map.entry(*local).or_insert_with(|| {
263 let s = ctx.local_next;
264 ctx.local_next += 1;
265 s
266 });
267 ctx.chunk.w(OP_STORELOCAL);
268 ctx.chunk.w2(slot);
269 },
270 _ => {},
271 }
272}
273
274fn compile_rval(rv: &Rvalue, fn_names: &[String], ctx: &mut Ctx) {
275 match rv {
276 Rvalue::Use(op) => compile_op(op, fn_names, ctx),
277 Rvalue::BinaryOp(op, l, r) => {
278 compile_op(l, fn_names, ctx);
279 compile_op(r, fn_names, ctx);
280 ctx.chunk.w(match op {
281 BinOp::Add => OP_ADD,
282 BinOp::Sub => OP_SUB,
283 BinOp::Mul => OP_MUL,
284 BinOp::Div => OP_DIV,
285 BinOp::Rem => OP_REM,
286 BinOp::Eq => OP_EQ,
287 BinOp::Ne => OP_NE,
288 BinOp::Lt => OP_LT,
289 BinOp::Le => OP_LE,
290 BinOp::Gt => OP_GT,
291 BinOp::Ge => OP_GE,
292 BinOp::And => OP_AND,
293 BinOp::Or => OP_OR,
294 _ => OP_NOP, });
296 },
297 Rvalue::UnaryOp(op, o) => {
298 compile_op(o, fn_names, ctx);
299 ctx.chunk.w(match op {
300 UnOp::Not => OP_NOT,
301 UnOp::Neg => OP_NEG,
302 _ => OP_NOP,
303 });
304 },
305 Rvalue::Call { func, args } => {
306 for arg in args {
307 compile_op(arg, fn_names, ctx);
308 }
309 match func {
310 Operand::Constant(Constant::Function(name)) => {
311 if let Some(idx) = fn_names.iter().position(|n| n == name) {
312 ctx.chunk.w(OP_CALL);
313 ctx.chunk.w2(idx as u16);
314 } else {
315 let sidx = ctx.chunk.add_str(name);
316 ctx.chunk.w(OP_CALLBUILTIN);
317 ctx.chunk.w2(sidx);
318 ctx.chunk.w2(args.len() as u16);
319 }
320 },
321 _ => {
322 compile_op(func, fn_names, ctx);
323 let sidx = ctx.chunk.add_str("__indirect");
324 ctx.chunk.w(OP_CALLBUILTIN);
325 ctx.chunk.w2(sidx);
326 ctx.chunk.w2(args.len() as u16);
327 },
328 }
329 },
330 Rvalue::Aggregate(_kind, ops) => {
331 for op in ops {
332 compile_op(op, fn_names, ctx);
333 }
334 ctx.chunk.w(OP_MAKELIST);
335 ctx.chunk.w2(ops.len() as u16);
336 },
337 Rvalue::GetIndex(obj, idx) => {
338 compile_op(obj, fn_names, ctx);
339 compile_op(idx, fn_names, ctx);
340 ctx.chunk.w(OP_GETINDEX);
341 },
342 _ => {
343 ctx.chunk.w(OP_PUSHNONE);
344 },
345 }
346}
347
348fn compile_op(op: &Operand, _fn_names: &[String], ctx: &mut Ctx) {
349 match op {
350 Operand::Copy(l) | Operand::Move(l) => {
351 let slot = ctx.local_map.get(l).copied().unwrap_or(0);
352 ctx.chunk.w(OP_LOADLOCAL);
353 ctx.chunk.w2(slot);
354 },
355 Operand::Constant(c) => match c {
356 Constant::I64(v) => {
357 ctx.chunk.w(OP_PUSHI64);
358 ctx.chunk.w8(*v);
359 },
360 Constant::F64(bits) => {
361 let idx = ctx.chunk.add_float(f64::from_bits(*bits));
362 ctx.chunk.w(OP_PUSHF64);
363 ctx.chunk.w2(idx);
364 },
365 Constant::Str(s) => {
366 let idx = ctx.chunk.add_str(s);
367 ctx.chunk.w(OP_PUSHSTR);
368 ctx.chunk.w2(idx);
369 },
370 Constant::Bool(b) => {
371 ctx.chunk.w(OP_PUSHBOOL);
372 ctx.chunk.w(if *b { 1 } else { 0 });
373 },
374 _ => {
375 ctx.chunk.w(OP_PUSHNONE);
376 },
377 },
378 }
379}
380
381fn compile_term(term: &Terminator, fn_names: &[String], ctx: &mut Ctx) {
382 match &term.kind {
383 TerminatorKind::Return => {
384 ctx.chunk.w(OP_LOADLOCAL);
385 ctx.chunk.w2(0);
386 ctx.chunk.w(OP_RET);
387 },
388 TerminatorKind::Goto { target } => {
389 ctx.chunk.w(OP_JUMP);
390 let pos = ctx.chunk.code.len();
391 ctx.chunk.w2(0);
392 ctx.patches.push((pos, target.0));
393 },
394 TerminatorKind::SwitchInt { discr, targets, otherwise } => {
395 compile_op(discr, fn_names, ctx);
396 if let Some((val, target)) = targets.first() {
397 ctx.chunk.w(OP_PUSHI64);
398 ctx.chunk.w8(*val);
399 ctx.chunk.w(OP_EQ);
400 ctx.chunk.w(OP_JUMPIFFALSE);
401 let pos = ctx.chunk.code.len();
402 ctx.chunk.w2(0);
403 ctx.patches.push((pos, target.0));
404 }
405 ctx.chunk.w(OP_JUMP);
406 let pos = ctx.chunk.code.len();
407 ctx.chunk.w2(0);
408 ctx.patches.push((pos, otherwise.0));
409 },
410 TerminatorKind::Unreachable => {
411 ctx.chunk.w(OP_HALT);
412 },
413 }
414}
415
416fn read_u8(code: &[u8], ip: usize) -> u8 {
417 code[ip]
418}
419
420fn read_u16(code: &[u8], ip: usize) -> u16 {
421 let mut bytes = [0u8; 2];
422 bytes.copy_from_slice(&code[ip..ip + 2]);
423 u16::from_le_bytes(bytes)
424}
425
426fn read_i64(code: &[u8], ip: usize) -> i64 {
427 let mut bytes = [0u8; 8];
428 bytes.copy_from_slice(&code[ip..ip + 8]);
429 i64::from_le_bytes(bytes)
430}
431
432struct Frame {
435 fn_index: usize,
436 ip: usize,
437 base: usize,
438 local_count: usize,
439}
440
441pub struct Vm {
442 stack: Vec<Value>,
443 program: Option<VmProgram>,
444 call_stack: Vec<Frame>,
445}
446
447impl Vm {
448 pub fn new() -> Self {
449 Self { stack: Vec::new(), program: None, call_stack: Vec::new() }
450 }
451
452 pub fn load(&mut self, program: VmProgram) {
453 self.program = Some(program);
454 }
455
456 pub fn run_main(&mut self) -> Result<(), String> {
457 let p = self.program.as_ref().ok_or("no program loaded")?;
458 if p.functions.is_empty() {
459 return Ok(());
460 }
461 let main_idx = p.main_index;
462 let func = &p.functions[main_idx];
463 let lc = func.chunk.local_count as usize;
464 for _ in 0..lc {
465 self.stack.push(Value::None);
466 }
467 self.call_stack
468 .push(Frame { fn_index: main_idx, ip: 0, base: 0, local_count: lc });
469 self.exec()
470 }
471
472 fn exec(&mut self) -> Result<(), String> {
473 loop {
474 if self.call_stack.is_empty() {
475 return Ok(());
476 }
477
478 let frame_ip = self.call_stack.last().unwrap().ip;
479
480 let fn_index = self.call_stack.last().unwrap().fn_index;
482 let (code, floats, strings) = {
483 let p = self.program.as_ref().unwrap();
484 let chunk = &p.functions[fn_index].chunk;
485 (
487 chunk.code.clone(),
488 chunk.floats.clone(),
489 chunk.strings.clone(),
490 )
491 };
492 let code_len = code.len();
493
494 if frame_ip >= code_len {
495 self.call_stack.pop();
496 return Err("unexpected end of code".into());
497 }
498
499 let op = read_u8(&code, frame_ip);
500 let mut ip = frame_ip + 1;
501
502 match op {
503 OP_PUSHI64 => {
504 let v = read_i64(&code, ip);
505 ip += 8;
506 self.stack.push(Value::Number(v as f64));
507 },
508 OP_PUSHF64 => {
509 let idx = read_u16(&code, ip) as usize;
510 ip += 2;
511 self.stack.push(Value::Number(floats[idx]));
512 },
513 OP_PUSHSTR => {
514 let idx = read_u16(&code, ip) as usize;
515 ip += 2;
516 self.stack.push(Value::Str(strings[idx].clone()));
517 },
518 OP_PUSHBOOL => {
519 let b = read_u8(&code, ip) != 0;
520 ip += 1;
521 self.stack.push(Value::Bool(b));
522 },
523 OP_PUSHNONE => self.stack.push(Value::None),
524 OP_POP => {
525 self.stack.pop();
526 },
527 OP_LOADLOCAL => {
528 let idx = read_u16(&code, ip) as usize;
529 ip += 2;
530 let base = self.call_stack.last().unwrap().base;
531 self.stack.push(self.stack[base + idx].clone());
532 },
533 OP_STORELOCAL => {
534 let idx = read_u16(&code, ip) as usize;
535 ip += 2;
536 let val = self.stack.pop().unwrap();
537 let base = self.call_stack.last().unwrap().base;
538 self.stack[base + idx] = val;
539 },
540 OP_ADD | OP_SUB | OP_MUL | OP_DIV | OP_REM => {
541 let b = self.stack.pop().unwrap();
542 let a = self.stack.pop().unwrap();
543 let r = match (op, &a, &b) {
544 (OP_ADD, Value::Str(s), v) => Value::Str(format!("{}{}", s, v.display())),
545 (OP_ADD, v, Value::Str(s)) => Value::Str(format!("{}{}", v.display(), s)),
546 (OP_ADD, Value::Number(a), Value::Number(b)) => Value::Number(a + b),
547 (OP_SUB, Value::Number(a), Value::Number(b)) => Value::Number(a - b),
548 (OP_MUL, Value::Number(a), Value::Number(b)) => Value::Number(a * b),
549 (OP_DIV, Value::Number(a), Value::Number(b)) => Value::Number(a / b),
550 (OP_REM, Value::Number(a), Value::Number(b)) => Value::Number(a % b),
551 _ => return Err("type error in arithmetic".into()),
552 };
553 self.stack.push(r);
554 },
555 OP_EQ | OP_NE | OP_LT | OP_LE | OP_GT | OP_GE => {
556 let b = self.stack.pop().unwrap();
557 let a = self.stack.pop().unwrap();
558 let r = match op {
559 OP_EQ => values_equal(&a, &b),
560 OP_NE => !values_equal(&a, &b),
561 OP_LT => num_cmp(&a, &b, |a, b| a < b),
562 OP_LE => num_cmp(&a, &b, |a, b| a <= b),
563 OP_GT => num_cmp(&a, &b, |a, b| a > b),
564 OP_GE => num_cmp(&a, &b, |a, b| a >= b),
565 _ => false,
566 };
567 self.stack.push(Value::Bool(r));
568 },
569 OP_AND => {
570 let b = self.stack.pop().unwrap();
571 let a = self.stack.pop().unwrap();
572 self.stack.push(Value::Bool(a.is_truthy() && b.is_truthy()));
573 },
574 OP_OR => {
575 let b = self.stack.pop().unwrap();
576 let a = self.stack.pop().unwrap();
577 self.stack.push(Value::Bool(a.is_truthy() || b.is_truthy()));
578 },
579 OP_NOT => {
580 let v = self.stack.pop().unwrap();
581 self.stack.push(Value::Bool(!v.is_truthy()));
582 },
583 OP_NEG => {
584 let v = self.stack.pop().unwrap();
585 if let Value::Number(n) = v {
586 self.stack.push(Value::Number(-n));
587 } else {
588 return Err("type error: negate non-number".into());
589 }
590 },
591 OP_CALL => {
592 let idx = read_u16(&code, ip) as usize;
593 ip += 2;
594 let (ac, lc) = {
595 let p = self.program.as_ref().unwrap();
596 (
597 p.functions[idx].arg_count as usize,
598 p.functions[idx].chunk.local_count as usize,
599 )
600 };
601 let extra = lc.saturating_sub(ac);
602 for _ in 0..extra {
603 self.stack.push(Value::None);
604 }
605 let new_base = self.stack.len() - lc;
606 self.call_stack.push(Frame {
607 fn_index: idx,
608 ip: 0,
609 base: new_base,
610 local_count: lc,
611 });
612 },
613 OP_CALLBUILTIN => {
614 let si = read_u16(&code, ip) as usize;
615 ip += 2;
616 let count = read_u16(&code, ip) as usize;
617 ip += 2;
618 let name = strings[si].clone();
619 let (canon, _) =
620 resolve_builtin(&name).map_err(|e| format!("{} in {}", e, name))?;
621 self.call_builtin(canon, count)?;
622 },
623 OP_RET => {
624 let val = self.stack.pop().unwrap_or(Value::None);
625 let _frame = self.call_stack.pop().unwrap();
626 if let Some(caller) = self.call_stack.last() {
627 self.stack.truncate(caller.base + caller.local_count);
628 self.stack.push(val);
629 } else {
630 self.stack.push(val);
631 return Ok(());
632 }
633 },
634 OP_JUMP => {
635 ip = read_u16(&code, ip) as usize;
636 },
637 OP_JUMPIFFALSE => {
638 let offset = read_u16(&code, ip) as usize;
639 ip += 2;
640 let cond = self.stack.pop().unwrap();
641 if !cond.is_truthy() {
642 ip = offset;
643 }
644 },
645 OP_MAKELIST => {
646 let count = read_u16(&code, ip) as usize;
647 ip += 2;
648 let mut items = Vec::with_capacity(count);
649 for _ in 0..count {
650 items.push(self.stack.pop().unwrap());
651 }
652 items.reverse();
653 self.stack.push(Value::List(items));
654 },
655 OP_GETINDEX => {
656 let idx_v = self.stack.pop().unwrap();
657 let obj = self.stack.pop().unwrap();
658 match (&obj, &idx_v) {
659 (Value::List(list), Value::Number(n)) => {
660 let i = *n as usize;
661 self.stack.push(if i < list.len() {
662 list[i].clone()
663 } else {
664 Value::None
665 });
666 },
667 _ => self.stack.push(Value::None),
668 }
669 },
670 OP_HALT => return Ok(()),
671 _ => return Err(format!("unknown opcode {} at ip {}", op, ip - 1)),
672 }
673
674 self.call_stack.last_mut().unwrap().ip = ip;
675 }
676 }
677
678 fn call_builtin(&mut self, name: &str, arg_count: usize) -> Result<(), String> {
679 match name {
680 "print" => {
681 if let Some(val) = self.stack.pop() {
682 println!("{}", val.display());
683 }
684 self.stack.push(Value::None);
685 },
686 "format" => {
687 let mut parts: Vec<String> = Vec::with_capacity(arg_count);
688 for _ in 0..arg_count {
689 if let Some(val) = self.stack.pop() {
690 parts.push(val.display());
691 }
692 }
693 parts.reverse();
694 if parts.is_empty() {
695 self.stack.push(Value::Str(String::new()));
696 return Ok(());
697 }
698 let fmt_str = parts.remove(0);
699 let mut result = fmt_str;
700 for part in parts {
701 result = result.replacen("{}", &part, 1);
702 }
703 self.stack.push(Value::Str(result));
704 },
705 "len" => {
706 let val = self.stack.pop().unwrap_or(Value::None);
707 let n = match &val {
708 Value::Str(s) => s.len() as f64,
709 Value::List(l) => l.len() as f64,
710 _ => 0.0,
711 };
712 self.stack.push(Value::Number(n));
713 },
714 "to_str" => {
715 let val = self.stack.pop().unwrap_or(Value::None);
716 self.stack.push(Value::Str(val.display()));
717 },
718 "sin" => {
719 let val = self.stack.pop().unwrap_or(Value::None);
720 if let Value::Number(n) = val {
721 self.stack.push(Value::Number(n.sin()));
722 } else {
723 self.stack.push(Value::Number(0.0));
724 }
725 },
726 "cos" => {
727 let val = self.stack.pop().unwrap_or(Value::None);
728 if let Value::Number(n) = val {
729 self.stack.push(Value::Number(n.cos()));
730 } else {
731 self.stack.push(Value::Number(0.0));
732 }
733 },
734 _ => return Err(format!("unimplemented builtin: {}", name)),
735 }
736 Ok(())
737 }
738}
739
740pub struct BytecodeBackend;
743
744impl CodegenBackend for BytecodeBackend {
745 fn emit(&mut self, program: &crate::MirProgram, out: &std::path::Path) -> anyhow::Result<()> {
746 let vm_prog = compile_mir_program(&program.mir);
747 let mut bytes = Vec::new();
748 bytes.extend_from_slice(b"LINGBC");
749 let fn_count = vm_prog.functions.len() as u32;
750 bytes.extend_from_slice(&fn_count.to_le_bytes());
751 for func in &vm_prog.functions {
752 let name_bytes = func.name.as_bytes();
753 bytes.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
754 bytes.extend_from_slice(name_bytes);
755 bytes.extend_from_slice(&func.arg_count.to_le_bytes());
756 bytes.extend_from_slice(&func.chunk.local_count.to_le_bytes());
757 bytes.extend_from_slice(&(func.chunk.code.len() as u32).to_le_bytes());
758 bytes.extend_from_slice(&func.chunk.code);
759 bytes.extend_from_slice(&(func.chunk.floats.len() as u32).to_le_bytes());
760 for &f in &func.chunk.floats {
761 bytes.extend_from_slice(&f.to_bits().to_le_bytes());
762 }
763 bytes.extend_from_slice(&(func.chunk.strings.len() as u32).to_le_bytes());
764 for s in &func.chunk.strings {
765 let sb = s.as_bytes();
766 bytes.extend_from_slice(&(sb.len() as u32).to_le_bytes());
767 bytes.extend_from_slice(sb);
768 }
769 }
770 std::fs::write(out, &bytes)?;
771 Ok(())
772 }
773}