Skip to main content

vihaco_module/
module.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4use crate::color::Themed;
5pub use crate::program_metadata::ProgramMetadata;
6
7/// A module for a single section.
8#[derive(Debug, Clone, PartialEq)]
9pub struct LocalModule<I, V, Ty, Info = NoInfo> {
10    pub code: Vec<I>,
11    pub functions: Vec<FunctionInfo<Ty>>,
12    pub labels: Vec<LabelInfo>,
13    pub constants: Vec<V>,
14    pub strings: Vec<String>,
15    pub main_function: Option<u32>,
16    pub source_symbols: Vec<SourceSymbolInfo>,
17    pub extra: Info,
18}
19
20impl<I, V, Ty, Info> Default for LocalModule<I, V, Ty, Info>
21where
22    Info: Default,
23{
24    fn default() -> Self {
25        Self {
26            code: Vec::new(),
27            functions: Vec::new(),
28            labels: Vec::new(),
29            constants: Vec::new(),
30            strings: Vec::new(),
31            main_function: None,
32            source_symbols: Vec::new(),
33            extra: Info::default(),
34        }
35    }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, vihaco_parser_derive::Parse)]
39#[syntax_class(metadata, open = "{", close = "}")]
40pub struct SourceSymbolInfo {
41    pub index: u32,
42    pub name: String,
43}
44
45#[derive(Debug, Clone, PartialEq, vihaco_parser_derive::Parse)]
46#[syntax_class(metadata, open = "{", close = "}")]
47pub struct FunctionInfo<Type> {
48    pub name: u32, // index into the string interner
49    pub signature: Signature<Type>,
50    /// Reserved local slots, including parameters, for this function.
51    pub local_count: u32,
52    pub start_address: u32, // corresponds to a label noop
53    pub end_address: u32,   // corresponds to a label noop
54    pub file: u32,
55}
56
57#[derive(Debug, Clone, PartialEq, vihaco_parser_derive::Parse)]
58#[syntax_class(metadata, open = "{", close = "}")]
59pub struct Signature<Ty> {
60    pub params: Vec<Parameter<Ty>>,
61    pub ret: Vec<Ty>,
62}
63
64#[derive(Debug, Clone, PartialEq, vihaco_parser_derive::Parse)]
65#[syntax_class(metadata, open = "{", close = "}")]
66pub struct Parameter<Ty> {
67    pub name: u32, // index into the string interner
68    pub ty: Ty,
69}
70
71#[derive(Debug, Clone, PartialEq, vihaco_parser_derive::Parse)]
72#[syntax_class(metadata, open = "{", close = "}")]
73pub struct LabelInfo {
74    pub address: u32,
75    pub name: u32, // index into the string interner
76}
77
78#[derive(Debug, Clone, PartialEq, Default, vihaco_parser_derive::Parse)]
79#[syntax_class(metadata)]
80#[pattern = "`{` `}`"]
81pub struct NoInfo;
82
83impl std::fmt::Display for NoInfo {
84    fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        Ok(())
86    }
87}
88
89impl<I, V, Ty, Info> std::fmt::Display for LocalModule<I, V, Ty, Info>
90where
91    I: std::fmt::Display,
92    V: std::fmt::Display,
93    Ty: std::fmt::Display,
94    Info: std::fmt::Display,
95{
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        ".text".keyword().fmt(f)?;
98        writeln!(f)?;
99
100        for (addr, inst) in self.code.iter().enumerate() {
101            write!(f, "0x{:04X} ", addr)?;
102            inst.fmt(f)?;
103            writeln!(f)?;
104        }
105
106        writeln!(f)?;
107        ".const".keyword().fmt(f)?;
108        writeln!(f)?;
109        for (const_idx, constant) in self.constants.iter().enumerate() {
110            write!(f, "0x{:04X} ", const_idx)?;
111            constant.fmt(f)?;
112            writeln!(f)?;
113        }
114
115        writeln!(f)?;
116        ".string".keyword().fmt(f)?;
117        writeln!(f)?;
118        for (string_idx, string) in self.strings.iter().enumerate() {
119            if string_idx > 0 {
120                writeln!(f)?;
121            }
122            write!(f, "0x{:04X} \"{}\"", string_idx, string.escape_default())?;
123        }
124
125        writeln!(f)?;
126        if !self.source_symbols.is_empty() {
127            ".machine".keyword().fmt(f)?;
128            writeln!(f, " symbols {{")?;
129            for symbol in &self.source_symbols {
130                writeln!(f, "  {}: {},", symbol.index, symbol.name)?;
131            }
132            writeln!(f, "}}")?;
133            writeln!(f)?;
134        }
135        writeln!(f)?;
136        ".feature".keyword().fmt(f)?;
137        writeln!(f)?;
138        self.extra.fmt(f)?;
139        Ok(())
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[derive(Debug, Clone, PartialEq)]
148    enum MockInst {
149        Push(u64),
150        Add,
151        Print,
152        Halt,
153    }
154
155    impl std::fmt::Display for MockInst {
156        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157            match self {
158                MockInst::Push(v) => write!(f, "push {}", v),
159                MockInst::Add => write!(f, "add"),
160                MockInst::Print => write!(f, "print"),
161                MockInst::Halt => write!(f, "halt"),
162            }
163        }
164    }
165
166    #[test]
167    fn test_module() {
168        let mut module: LocalModule<MockInst, u64, &str> = LocalModule::default();
169        module.code.push(MockInst::Push(42));
170        module.code.push(MockInst::Push(42));
171        module.code.push(MockInst::Add);
172        module.code.push(MockInst::Print);
173        module.code.push(MockInst::Halt);
174
175        module.constants.push(42);
176        module.constants.push(100);
177
178        module.strings.push("hello".to_string());
179        module.strings.push("world".to_string());
180        println!("{:#}", module);
181    }
182}