1use super::{Backend, GeneratedFiles};
4use crate::{
5 config::GaiaConfig,
6 instruction::GaiaInstruction,
7 program::{GaiaConstant, GaiaFunction, GaiaProgram},
8 types::GaiaType,
9};
10use gaia_types::{
11 helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
12 *,
13};
14use std::collections::HashMap;
15use crate::adapters::FunctionMapper;
16
17#[derive(Default)]
19pub struct WasiBackend {}
20
21impl Backend for WasiBackend {
22 fn name(&self) -> &'static str {
23 "WASI"
24 }
25
26 fn primary_target(&self) -> CompilationTarget {
27 CompilationTarget {
28 build: Architecture::WASM32,
29 host: AbiCompatible::WebAssemblyTextFormat,
30 target: ApiCompatible::WASI,
31 }
32 }
33
34 fn match_score(&self, target: &CompilationTarget) -> f32 {
35 match target.host {
36 AbiCompatible::WebAssemblyTextFormat => 10.0,
37 AbiCompatible::Unknown => match target.build {
38 Architecture::WASM32 => 5.0,
40 Architecture::WASM64 => 0.0,
41 _ => -100.0,
42 },
43 _ => -100.0,
44 }
45 }
46
47 fn generate(&self, program: &GaiaProgram, _config: &GaiaConfig) -> Result<GeneratedFiles> {
48 let mut files = HashMap::new();
49 files.insert("main.wasm".to_string(), compile(program)?);
50 Ok(GeneratedFiles { files, diagnostics: vec![] })
51 }
52}
53
54impl WasiBackend {
55 pub fn generate(program: &GaiaProgram) -> Result<Vec<u8>> {
57 let mut context = create_wasi_context()?;
58 compile_program(&mut context, program)?;
59 generate_wasm_bytecode(&context)
60 }
61}
62
63pub fn compile(program: &GaiaProgram) -> Result<Vec<u8>> {
65 WasiBackend::generate(program)
66}
67
68fn create_wasi_context() -> Result<WasiContext> {
70 Ok(WasiContext::new())
73}
74
75fn compile_program(context: &mut WasiContext, program: &GaiaProgram) -> Result<()> {
77 for function in &program.functions {
79 compile_function(context, function)?;
80 }
81
82 Ok(())
83}
84
85fn compile_function(context: &mut WasiContext, function: &GaiaFunction) -> Result<()> {
87 start_function(context, &function.name, &function.parameters, &function.return_type)?;
89
90 for instruction in &function.instructions {
92 compile_instruction(context, instruction)?;
93 }
94
95 end_function(context)?;
97
98 Ok(())
99}
100
101fn compile_instruction(context: &mut WasiContext, instruction: &GaiaInstruction) -> Result<()> {
103 match instruction {
104 GaiaInstruction::LoadConstant(constant) => compile_load_constant(context, constant),
105 GaiaInstruction::LoadLocal(index) => compile_load_local(context, (*index).try_into().unwrap()),
106 GaiaInstruction::StoreLocal(index) => compile_store_local(context, (*index).try_into().unwrap()),
107 GaiaInstruction::LoadGlobal(name) => compile_load_global(context, name),
108 GaiaInstruction::StoreGlobal(name) => compile_store_global(context, name),
109 GaiaInstruction::LoadArgument(index) => compile_load_argument(context, (*index).try_into().unwrap()),
110 GaiaInstruction::Add => compile_add(context),
111 GaiaInstruction::Subtract => compile_subtract(context),
112 GaiaInstruction::Multiply => compile_multiply(context),
113 GaiaInstruction::Divide => compile_divide(context),
114 GaiaInstruction::Remainder => compile_remainder(context),
115 GaiaInstruction::BitwiseAnd => compile_bitwise_and(context),
116 GaiaInstruction::BitwiseOr => compile_bitwise_or(context),
117 GaiaInstruction::BitwiseXor => compile_bitwise_xor(context),
118 GaiaInstruction::BitwiseNot => compile_bitwise_not(context),
119 GaiaInstruction::LogicalAnd => compile_logical_and(context),
120 GaiaInstruction::LogicalOr => compile_logical_or(context),
121 GaiaInstruction::LogicalNot => compile_logical_not(context),
122 GaiaInstruction::ShiftLeft => compile_left_shift(context),
123 GaiaInstruction::ShiftRight => compile_right_shift(context),
124 GaiaInstruction::Negate => compile_negate(context),
125 GaiaInstruction::Equal => compile_equal(context),
126 GaiaInstruction::NotEqual => compile_not_equal(context),
127 GaiaInstruction::LessThan => compile_less_than(context),
128 GaiaInstruction::GreaterThan => compile_greater_than(context),
129 GaiaInstruction::GreaterThanOrEqual => compile_greater_than_or_equal(context),
130 GaiaInstruction::LessThanOrEqual => compile_less_than_or_equal(context),
131 GaiaInstruction::Jump(label) => compile_branch(context, label),
132 GaiaInstruction::JumpIfTrue(label) => compile_branch_if_true(context, label),
133 GaiaInstruction::JumpIfFalse(label) => compile_branch_if_false(context, label),
134 GaiaInstruction::Call(function_name, _arg_count) => compile_call(context, function_name),
135 GaiaInstruction::Return => compile_return(context),
136 GaiaInstruction::Label(name) => compile_label(context, name),
137 GaiaInstruction::Duplicate => compile_duplicate(context),
138 GaiaInstruction::Pop => compile_pop(context),
139 GaiaInstruction::Convert(from_type, to_type) => compile_convert(context, from_type, to_type),
141 GaiaInstruction::LoadIndirect(gaia_type) => compile_load_indirect(context, gaia_type),
143 GaiaInstruction::StoreIndirect(gaia_type) => compile_store_indirect(context, gaia_type),
144 GaiaInstruction::Box(gaia_type) => compile_box(context, gaia_type),
145 GaiaInstruction::Unbox(gaia_type) => compile_unbox(context, gaia_type),
146 GaiaInstruction::NewArray(elem_type, size) => compile_new_array(context, elem_type, *size),
147 GaiaInstruction::LoadElement(elem_type) => compile_load_element(context, elem_type),
148 GaiaInstruction::StoreElement(elem_type) => compile_store_element(context, elem_type),
149 GaiaInstruction::ArrayLength => compile_array_length(context),
150 _ => Ok(())
151 }
152}
153
154fn compile_load_constant(context: &mut WasiContext, constant: &GaiaConstant) -> Result<()> {
158 match constant {
159 GaiaConstant::Integer8(value) => {
160 context.emit_i32_const(*value as i32)
162 }
163 GaiaConstant::Integer16(value) => {
164 context.emit_i32_const(*value as i32)
166 }
167 GaiaConstant::Integer32(value) => {
168 context.emit_i32_const(*value)
170 }
171 GaiaConstant::Integer64(value) => {
172 context.emit_i64_const(*value)
174 }
175 GaiaConstant::Float32(value) => {
176 context.emit_f32_const(*value)
178 }
179 GaiaConstant::Float64(value) => {
180 context.emit_f64_const(*value)
182 }
183 GaiaConstant::String(value) => {
184 context.emit_string_const(value)
186 }
187 GaiaConstant::Boolean(value) => {
188 context.emit_i32_const(if *value { 1 } else { 0 })
190 }
191 GaiaConstant::Null => {
192 context.emit_i32_const(0)
194 }
195 }
196}
197
198fn compile_load_local(context: &mut WasiContext, index: u32) -> Result<()> {
199 context.emit_local_get(index)
201}
202
203fn compile_store_local(context: &mut WasiContext, index: u32) -> Result<()> {
204 context.emit_local_set(index)
206}
207
208fn compile_load_argument(context: &mut WasiContext, index: u32) -> Result<()> {
209 context.emit_local_get(index)
211}
212
213fn compile_add(context: &mut WasiContext) -> Result<()> {
214 context.emit_i32_add()
216}
217
218fn compile_subtract(context: &mut WasiContext) -> Result<()> {
219 context.emit_i32_sub()
221}
222
223fn compile_multiply(context: &mut WasiContext) -> Result<()> {
224 context.emit_i32_mul()
226}
227
228fn compile_divide(context: &mut WasiContext) -> Result<()> {
229 context.emit_i32_div_s()
231}
232
233fn compile_equal(context: &mut WasiContext) -> Result<()> {
234 context.emit_i32_eq()
236}
237
238fn compile_not_equal(context: &mut WasiContext) -> Result<()> {
239 context.emit_i32_ne()
241}
242
243fn compile_less_than(context: &mut WasiContext) -> Result<()> {
244 context.emit_i32_lt_s()
246}
247
248fn compile_greater_than(context: &mut WasiContext) -> Result<()> {
249 context.emit_i32_gt_s()
251}
252
253fn compile_branch(context: &mut WasiContext, label: &str) -> Result<()> {
254 context.emit_br(label)
256}
257
258fn compile_branch_if_true(context: &mut WasiContext, label: &str) -> Result<()> {
259 context.emit_if_br(label)
261}
262
263fn compile_branch_if_false(context: &mut WasiContext, label: &str) -> Result<()> {
264 context.emit_if_not_br(label)
266}
267
268fn compile_call(_context: &mut WasiContext, function_name: &str) -> Result<()> {
269 let mapper = FunctionMapper::new();
271 let wasi_target = CompilationTarget {
272 build: Architecture::WASM32,
273 host: AbiCompatible::WebAssemblyTextFormat,
274 target: ApiCompatible::WASI,
275 };
276 let _mapped_name = mapper.map_function(&wasi_target, function_name);
277
278 todo!()
280}
281
282fn compile_return(context: &mut WasiContext) -> Result<()> {
283 context.emit_return()
285}
286
287fn compile_label(context: &mut WasiContext, name: &str) -> Result<()> {
288 context.define_label(name)
290}
291
292fn compile_duplicate(context: &mut WasiContext) -> Result<()> {
293 context.emit_local_tee(0) }
296
297fn compile_pop(context: &mut WasiContext) -> Result<()> {
298 context.emit_drop()
300}
301
302fn compile_load_field(context: &mut WasiContext, field_name: &str) -> Result<()> {
303 context.emit_struct_get(field_name)
306}
307
308fn compile_store_field(context: &mut WasiContext, field_name: &str) -> Result<()> {
309 context.emit_struct_set(field_name)
312}
313
314fn compile_new_object(context: &mut WasiContext, type_name: &str) -> Result<()> {
315 context.emit_new_object(type_name)
318}
319
320fn compile_convert(context: &mut WasiContext, from_type: &GaiaType, to_type: &GaiaType) -> Result<()> {
321 match (from_type, to_type) {
322 (GaiaType::Integer32, GaiaType::Integer64) => context.emit_i64_extend_i32_s(),
323 (GaiaType::Integer64, GaiaType::Integer32) => context.emit_i32_wrap_i64(),
324 (GaiaType::Integer32, GaiaType::Float32) => context.emit_f32_convert_i32_s(),
325 (GaiaType::Integer32, GaiaType::Float64) => context.emit_f64_convert_i32_s(),
326 (GaiaType::Integer64, GaiaType::Float32) => context.emit_f32_convert_i64_s(),
327 (GaiaType::Integer64, GaiaType::Float64) => context.emit_f64_convert_i64_s(),
328 (GaiaType::Float32, GaiaType::Integer32) => context.emit_i32_trunc_f32_s(),
329 (GaiaType::Float32, GaiaType::Integer64) => context.emit_i64_trunc_f32_s(),
330 (GaiaType::Float64, GaiaType::Integer32) => context.emit_i32_trunc_f64_s(),
331 (GaiaType::Float64, GaiaType::Integer64) => context.emit_i64_trunc_f64_s(),
332 (GaiaType::Float32, GaiaType::Float64) => context.emit_f64_promote_f32(),
333 (GaiaType::Float64, GaiaType::Float32) => context.emit_f32_demote_f64(),
334 _ => Err(GaiaError::not_implemented("WASI type conversion")),
335 }
336}
337
338fn compile_store_argument(context: &mut WasiContext, index: u32) -> Result<()> {
339 context.emit_local_set(index)
341}
342
343fn compile_remainder(context: &mut WasiContext) -> Result<()> {
344 context.emit_i32_rem_s()
346}
347
348fn compile_bitwise_and(context: &mut WasiContext) -> Result<()> {
349 context.emit_i32_and()
351}
352
353fn compile_bitwise_or(context: &mut WasiContext) -> Result<()> {
354 context.emit_i32_or()
356}
357
358fn compile_bitwise_xor(context: &mut WasiContext) -> Result<()> {
359 context.emit_i32_xor()
361}
362
363fn compile_bitwise_not(context: &mut WasiContext) -> Result<()> {
364 context.emit_i32_const(-1)?;
366 context.emit_i32_xor()
367}
368
369fn compile_logical_and(context: &mut WasiContext) -> Result<()> {
370 compile_bitwise_and(context)
372}
373
374fn compile_logical_or(context: &mut WasiContext) -> Result<()> {
375 compile_bitwise_or(context)
377}
378
379fn compile_logical_not(context: &mut WasiContext) -> Result<()> {
380 context.emit_i32_const(1)?;
382 context.emit_i32_xor()
383}
384
385fn compile_left_shift(context: &mut WasiContext) -> Result<()> {
386 context.emit_i32_shl()
388}
389
390fn compile_right_shift(context: &mut WasiContext) -> Result<()> {
391 context.emit_i32_shr_s()
393}
394
395fn compile_negate(context: &mut WasiContext) -> Result<()> {
396 context.emit_i32_const(0)?;
398 context.emit_swap()?;
399 context.emit_i32_sub()
400}
401
402fn compile_greater_than_or_equal(context: &mut WasiContext) -> Result<()> {
403 context.emit_i32_ge_s()
405}
406
407fn compile_less_than_or_equal(context: &mut WasiContext) -> Result<()> {
408 context.emit_i32_le_s()
410}
411
412fn compile_string_constant(context: &mut WasiContext, value: &str) -> Result<()> {
413 context.emit_string_const(value)
415}
416
417fn compile_load_global(_context: &mut WasiContext, _name: &str) -> Result<()> {
418 Err(GaiaError::not_implemented("WASI load global"))
420}
421
422fn compile_store_global(_context: &mut WasiContext, _name: &str) -> Result<()> {
423 Err(GaiaError::not_implemented("WASI store global"))
425}
426
427fn start_function(
429 _context: &mut WasiContext,
430 _name: &str,
431 _parameters: &[GaiaType],
432 _return_type: &Option<GaiaType>,
433) -> Result<()> {
434 Err(GaiaError::not_implemented("function start compilation"))
437}
438
439fn end_function(_context: &mut WasiContext) -> Result<()> {
440 Err(GaiaError::not_implemented("function end compilation"))
443}
444
445fn generate_wasm_bytecode(_context: &WasiContext) -> Result<Vec<u8>> {
447 Err(GaiaError::not_implemented("WebAssembly bytecode generation"))
450}
451
452struct WasiContext {
454 #[allow(dead_code)]
455 bytecode: Vec<u8>,
456}
457
458impl WasiContext {
459 fn new() -> Self {
460 WasiContext { bytecode: Vec::new() }
461 }
462
463 fn emit_i32_const(&mut self, _value: i32) -> Result<()> {
465 Err(GaiaError::not_implemented("i32.const emission"))
466 }
467
468 fn emit_i64_const(&mut self, _value: i64) -> Result<()> {
469 Err(GaiaError::not_implemented("i64.const emission"))
470 }
471
472 fn emit_f32_const(&mut self, _value: f32) -> Result<()> {
473 Err(GaiaError::not_implemented("f32.const emission"))
474 }
475
476 fn emit_f64_const(&mut self, _value: f64) -> Result<()> {
477 Err(GaiaError::not_implemented("f64.const emission"))
478 }
479
480 fn emit_local_get(&mut self, _index: u32) -> Result<()> {
481 Err(GaiaError::not_implemented("local.get emission"))
482 }
483
484 fn emit_local_set(&mut self, _index: u32) -> Result<()> {
485 Err(GaiaError::not_implemented("local.set emission"))
486 }
487
488 fn emit_i32_add(&mut self) -> Result<()> {
489 Err(GaiaError::not_implemented("i32.add emission"))
490 }
491
492 fn emit_i32_sub(&mut self) -> Result<()> {
493 Err(GaiaError::not_implemented("i32.sub emission"))
494 }
495
496 fn emit_i32_mul(&mut self) -> Result<()> {
497 Err(GaiaError::not_implemented("i32.mul emission"))
498 }
499
500 fn emit_i32_div_s(&mut self) -> Result<()> {
501 Err(GaiaError::not_implemented("i32.div_s emission"))
502 }
503
504 fn emit_i32_eq(&mut self) -> Result<()> {
505 Err(GaiaError::not_implemented("i32.eq emission"))
506 }
507
508 fn emit_i32_ne(&mut self) -> Result<()> {
509 Err(GaiaError::not_implemented("i32.ne emission"))
510 }
511
512 fn emit_i32_lt_s(&mut self) -> Result<()> {
513 Err(GaiaError::not_implemented("i32.lt_s emission"))
514 }
515
516 fn emit_i32_gt_s(&mut self) -> Result<()> {
517 Err(GaiaError::not_implemented("i32.gt_s emission"))
518 }
519
520 fn emit_br(&mut self, _label: &str) -> Result<()> {
521 Err(GaiaError::not_implemented("br emission"))
522 }
523
524 #[allow(dead_code)]
525 fn emit_br_if(&mut self, _label: &str) -> Result<()> {
526 Err(GaiaError::not_implemented("br_if emission"))
527 }
528
529 #[allow(dead_code)]
530 fn emit_call(&mut self, _function_name: &str) -> Result<()> {
531 Err(GaiaError::not_implemented("call emission"))
532 }
533
534 fn emit_return(&mut self) -> Result<()> {
535 Err(GaiaError::not_implemented("return emission"))
536 }
537
538 fn emit_drop(&mut self) -> Result<()> {
539 Err(GaiaError::not_implemented("drop emission"))
540 }
541
542 #[allow(dead_code)]
543 fn emit_load_field(&mut self, _field_name: &str) -> Result<()> {
544 Err(GaiaError::not_implemented("load field emission"))
545 }
546
547 #[allow(dead_code)]
548 fn emit_store_field(&mut self, _field_name: &str) -> Result<()> {
549 Err(GaiaError::not_implemented("store field emission"))
550 }
551
552 fn emit_new_object(&mut self, _type_name: &str) -> Result<()> {
553 Err(GaiaError::not_implemented("new object emission"))
554 }
555
556 fn emit_i64_extend_i32_s(&mut self) -> Result<()> {
558 Err(GaiaError::not_implemented("i64.extend_i32_s emission"))
559 }
560
561 fn emit_i32_wrap_i64(&mut self) -> Result<()> {
562 Err(GaiaError::not_implemented("i32.wrap_i64 emission"))
563 }
564
565 fn emit_f32_convert_i32_s(&mut self) -> Result<()> {
566 Err(GaiaError::not_implemented("f32.convert_i32_s emission"))
567 }
568
569 fn emit_f64_convert_i32_s(&mut self) -> Result<()> {
570 Err(GaiaError::not_implemented("f64.convert_i32_s emission"))
571 }
572
573 fn emit_f32_convert_i64_s(&mut self) -> Result<()> {
574 Err(GaiaError::not_implemented("f32.convert_i64_s emission"))
575 }
576
577 fn emit_f64_convert_i64_s(&mut self) -> Result<()> {
578 Err(GaiaError::not_implemented("f64.convert_i64_s emission"))
579 }
580
581 fn emit_i32_trunc_f32_s(&mut self) -> Result<()> {
582 Err(GaiaError::not_implemented("i32.trunc_f32_s emission"))
583 }
584
585 fn emit_i64_trunc_f32_s(&mut self) -> Result<()> {
586 Err(GaiaError::not_implemented("i64.trunc_f32_s emission"))
587 }
588
589 fn emit_i32_trunc_f64_s(&mut self) -> Result<()> {
590 Err(GaiaError::not_implemented("i32.trunc_f64_s emission"))
591 }
592
593 fn emit_i64_trunc_f64_s(&mut self) -> Result<()> {
594 Err(GaiaError::not_implemented("i64.trunc_f64_s emission"))
595 }
596
597 fn emit_f64_promote_f32(&mut self) -> Result<()> {
598 Err(GaiaError::not_implemented("f64.promote_f32 emission"))
599 }
600
601 fn emit_f32_demote_f64(&mut self) -> Result<()> {
602 Err(GaiaError::not_implemented("f32.demote_f64 emission"))
603 }
604
605 fn emit_string_const(&mut self, _value: &str) -> Result<()> {
606 Err(GaiaError::not_implemented("string const emission"))
607 }
608
609 fn emit_if_br(&mut self, _label: &str) -> Result<()> {
610 Err(GaiaError::not_implemented("if br emission"))
611 }
612
613 fn emit_if_not_br(&mut self, _label: &str) -> Result<()> {
614 Err(GaiaError::not_implemented("if not br emission"))
615 }
616
617 fn define_label(&mut self, _name: &str) -> Result<()> {
618 Err(GaiaError::not_implemented("label definition"))
619 }
620
621 fn emit_local_tee(&mut self, _index: u32) -> Result<()> {
622 Err(GaiaError::not_implemented("local.tee emission"))
623 }
624
625 fn emit_struct_get(&mut self, _field_name: &str) -> Result<()> {
626 Err(GaiaError::not_implemented("wasm<struct.get>"))
627 }
628
629 fn emit_struct_set(&mut self, _field_name: &str) -> Result<()> {
630 Err(GaiaError::not_implemented("wasm struct.set"))
631 }
632
633 fn emit_i32_rem_s(&mut self) -> Result<()> {
635 Err(GaiaError::not_implemented("wasm i32.rem_s"))
636 }
637
638 fn emit_i32_and(&mut self) -> Result<()> {
639 Err(GaiaError::not_implemented("wasm i32.and"))
640 }
641
642 fn emit_i32_or(&mut self) -> Result<()> {
643 Err(GaiaError::not_implemented("wasm i32.or"))
644 }
645
646 fn emit_i32_xor(&mut self) -> Result<()> {
647 Err(GaiaError::not_implemented("wasm i32.xor"))
648 }
649
650 fn emit_i32_shl(&mut self) -> Result<()> {
651 Err(GaiaError::not_implemented("wasm i32.shl"))
652 }
653
654 fn emit_i32_shr_s(&mut self) -> Result<()> {
655 Err(GaiaError::not_implemented("wasm i32.shr_s"))
656 }
657
658 fn emit_swap(&mut self) -> Result<()> {
659 Err(GaiaError::not_implemented("wasm stack swap"))
660 }
661
662 fn emit_i32_ge_s(&mut self) -> Result<()> {
663 Err(GaiaError::not_implemented("wasm i32.ge_s"))
664 }
665
666 fn emit_i32_le_s(&mut self) -> Result<()> {
667 Err(GaiaError::not_implemented("wasm i32.le_s"))
668 }
669}
670
671fn compile_load_address(_context: &mut WasiContext, _index: u32) -> Result<()> {
673 Err(GaiaError::not_implemented("WASI load address"))
675}
676
677fn compile_load_indirect(_context: &mut WasiContext, _gaia_type: &GaiaType) -> Result<()> {
678 Err(GaiaError::not_implemented("WASI load indirect"))
680}
681
682fn compile_store_indirect(_context: &mut WasiContext, _gaia_type: &GaiaType) -> Result<()> {
683 Err(GaiaError::not_implemented("WASI store indirect"))
685}
686
687fn compile_box(_context: &mut WasiContext, _gaia_type: &GaiaType) -> Result<()> {
688 Err(GaiaError::not_implemented("WASI box operation"))
690}
691
692fn compile_unbox(_context: &mut WasiContext, _gaia_type: &GaiaType) -> Result<()> {
693 Err(GaiaError::not_implemented("WASI unbox operation"))
695}
696
697fn compile_new_array(_context: &mut WasiContext, _elem_type: &GaiaType, _size: usize) -> Result<()> {
698 Err(GaiaError::not_implemented("WASI new array"))
700}
701
702fn compile_load_element(_context: &mut WasiContext, _elem_type: &GaiaType) -> Result<()> {
703 Err(GaiaError::not_implemented("WASI load element"))
705}
706
707fn compile_store_element(_context: &mut WasiContext, _elem_type: &GaiaType) -> Result<()> {
708 Err(GaiaError::not_implemented("WASI store element"))
710}
711
712fn compile_array_length(_context: &mut WasiContext) -> Result<()> {
713 Err(GaiaError::not_implemented("WASI array length"))
715}