Skip to main content

gaia_assembler/backends/nyar/
mod.rs

1use crate::{
2    backends::{Backend, GeneratedFiles},
3    config::GaiaConfig,
4    instruction::{CmpCondition, CoreInstruction, GaiaInstruction, ManagedInstruction},
5    program::{GaiaFunction, GaiaModule},
6};
7use gaia_binary::{BinaryWriter, Leb128};
8use gaia_types::{
9    helpers::{Architecture, ArtifactType, CompilationTarget},
10    Result,
11};
12use nyar_assembler::program::{
13    instructions::NyarCodec,
14    pool::NyarConstantPool,
15    types::{NyarChunk, NyarConstant, NyarInstruction, NyarModule},
16};
17use std::collections::HashMap;
18
19/// Nyar backend for Gaia assembler.
20///
21/// This backend translates Gaia IR into Nyar VM instructions.
22pub struct NyarBackend;
23
24impl Backend for NyarBackend {
25    fn name(&self) -> &'static str {
26        "nyar"
27    }
28
29    fn primary_target(&self) -> CompilationTarget {
30        CompilationTarget::new("nyar", "nyar", "nyar")
31    }
32
33    fn artifact_type(&self) -> ArtifactType {
34        ArtifactType::Executable
35    }
36
37    fn match_score(&self, target: &CompilationTarget) -> f32 {
38        if target.build == Architecture::Nyar {
39            100.0
40        }
41        else {
42            0.0
43        }
44    }
45
46    fn generate(&self, program: &GaiaModule, _config: &GaiaConfig) -> Result<GeneratedFiles> {
47        let mut nyar_module = NyarModule::default();
48        let mut constant_pool = NyarConstantPool::new();
49
50        for func in &program.functions {
51            let chunk = self.translate_function(func, &mut constant_pool)?;
52            nyar_module.chunks.push(chunk);
53        }
54
55        nyar_module.constants = constant_pool.pool;
56
57        Ok(GeneratedFiles {
58            artifact_type: ArtifactType::Executable,
59            files: HashMap::new(),
60            custom: Some(std::sync::Arc::new(nyar_module)),
61            diagnostics: vec![],
62        })
63    }
64}
65
66impl NyarBackend {
67    fn translate_function(&self, func: &GaiaFunction, pool: &mut NyarConstantPool) -> Result<NyarChunk> {
68        let mut chunk = NyarChunk::default();
69        let mut instructions = Vec::new();
70
71        for block in &func.blocks {
72            for inst in &block.instructions {
73                self.translate_instruction(inst, &mut instructions, pool)?;
74            }
75            // Handle terminator
76            self.translate_terminator(&block.terminator, &mut instructions, pool)?;
77        }
78
79        let mut writer = BinaryWriter::<Vec<u8>, Leb128>::new(Vec::new());
80        for inst in instructions {
81            inst.encode(&mut writer).map_err(|e| gaia_types::GaiaError::custom_error(e.to_string()))?;
82        }
83        chunk.code = writer.into_inner();
84
85        Ok(chunk)
86    }
87
88    fn translate_instruction(
89        &self,
90        inst: &GaiaInstruction,
91        out: &mut Vec<NyarInstruction>,
92        pool: &mut NyarConstantPool,
93    ) -> Result<()> {
94        match inst {
95            GaiaInstruction::Core(core) => self.translate_core(core, out, pool),
96            GaiaInstruction::Managed(managed) => self.translate_managed(managed, out, pool),
97            GaiaInstruction::Domain(_) => Ok(()),
98        }
99    }
100
101    fn translate_core(
102        &self,
103        inst: &CoreInstruction,
104        out: &mut Vec<NyarInstruction>,
105        pool: &mut NyarConstantPool,
106    ) -> Result<()> {
107        use crate::program::GaiaConstant;
108        match inst {
109            CoreInstruction::PushConstant(c) => match c {
110                GaiaConstant::I64(v) => out.push(NyarInstruction::I64Const(*v)),
111                GaiaConstant::F64(v) => out.push(NyarInstruction::F64Const(*v)),
112                GaiaConstant::I32(v) => out.push(NyarInstruction::I64Const(*v as i64)),
113                GaiaConstant::F32(v) => out.push(NyarInstruction::F64Const(*v as f64)),
114                GaiaConstant::String(s) => {
115                    let idx = pool.add(NyarConstant::String(s.clone()));
116                    out.push(NyarInstruction::Push(idx));
117                }
118                _ => {}
119            },
120            CoreInstruction::Add(ty) => {
121                if ty.is_integer() {
122                    out.push(NyarInstruction::I64Add);
123                }
124                else if ty.is_float() {
125                    out.push(NyarInstruction::F64Add);
126                }
127            }
128            CoreInstruction::Sub(ty) => {
129                if ty.is_integer() {
130                    out.push(NyarInstruction::I64Sub);
131                }
132                else if ty.is_float() {
133                    out.push(NyarInstruction::F64Sub);
134                }
135            }
136            CoreInstruction::Mul(ty) => {
137                if ty.is_integer() {
138                    out.push(NyarInstruction::I64Mul);
139                }
140                else if ty.is_float() {
141                    out.push(NyarInstruction::F64Mul);
142                }
143            }
144            CoreInstruction::Div(ty) => {
145                if ty.is_integer() {
146                    out.push(NyarInstruction::I64DivS);
147                }
148                else if ty.is_float() {
149                    out.push(NyarInstruction::F64Div);
150                }
151            }
152            CoreInstruction::Ret => out.push(NyarInstruction::Return),
153            CoreInstruction::LoadLocal(idx, _) => out.push(NyarInstruction::LoadLocal(*idx as u8)),
154            CoreInstruction::StoreLocal(idx, _) => out.push(NyarInstruction::StoreLocal(*idx as u8)),
155            CoreInstruction::LoadArg(idx, _) => out.push(NyarInstruction::LoadLocal(*idx as u8)),
156            CoreInstruction::StoreArg(idx, _) => out.push(NyarInstruction::StoreLocal(*idx as u8)),
157            CoreInstruction::Pop => out.push(NyarInstruction::Pop),
158            CoreInstruction::Dup => out.push(NyarInstruction::Dup(0)),
159            CoreInstruction::Cmp(cond, ty) => {
160                if ty.is_integer() {
161                    match cond {
162                        CmpCondition::Eq => out.push(NyarInstruction::I64Eq),
163                        CmpCondition::Ne => out.push(NyarInstruction::I64Ne),
164                        CmpCondition::Lt => out.push(NyarInstruction::I64LtS),
165                        CmpCondition::Le => out.push(NyarInstruction::I64LeS),
166                        CmpCondition::Gt => out.push(NyarInstruction::I64GtS),
167                        CmpCondition::Ge => out.push(NyarInstruction::I64GeS),
168                    }
169                }
170                else if ty.is_float() {
171                    match cond {
172                        CmpCondition::Eq => out.push(NyarInstruction::F64Eq),
173                        CmpCondition::Ne => out.push(NyarInstruction::F64Ne),
174                        CmpCondition::Lt => out.push(NyarInstruction::F64Lt),
175                        CmpCondition::Le => out.push(NyarInstruction::F64Le),
176                        CmpCondition::Gt => out.push(NyarInstruction::F64Gt),
177                        CmpCondition::Ge => out.push(NyarInstruction::F64Ge),
178                    }
179                }
180            }
181            _ => {}
182        }
183        Ok(())
184    }
185
186    fn translate_managed(
187        &self,
188        inst: &ManagedInstruction,
189        out: &mut Vec<NyarInstruction>,
190        pool: &mut NyarConstantPool,
191    ) -> Result<()> {
192        match inst {
193            ManagedInstruction::Initiate(args) => out.push(NyarInstruction::Initiate(*args as u8)),
194            ManagedInstruction::Finalize => out.push(NyarInstruction::Finalize),
195            _ => {}
196        }
197        Ok(())
198    }
199
200    fn translate_terminator(
201        &self,
202        term: &crate::program::GaiaTerminator,
203        out: &mut Vec<NyarInstruction>,
204        pool: &mut NyarConstantPool,
205    ) -> Result<()> {
206        use crate::program::GaiaTerminator::*;
207        match term {
208            Return => out.push(NyarInstruction::Return),
209            Halt => out.push(NyarInstruction::Halt),
210            Jump(_) => {
211                out.push(NyarInstruction::Jump(0));
212            }
213            Branch { .. } => {
214                out.push(NyarInstruction::JumpIfFalse(0));
215            }
216            Call { callee, args_count, .. } => {
217                let idx = pool.add(NyarConstant::String(callee.clone()));
218                out.push(NyarInstruction::Call(idx, *args_count as u8));
219            }
220        }
221        Ok(())
222    }
223}