1use crate::types::Type;
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct IR {
10 pub modules: Vec<Module>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Module {
15 pub name: String,
16 pub imports: Vec<Import>,
17 pub types: Vec<TypeDefinition>,
18 pub constants: Vec<Constant>,
19 pub metadata: Metadata,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct Import {
24 pub path: String,
25 pub alias: Option<String>,
26 pub items: Vec<String>, }
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct TypeDefinition {
31 pub name: String,
32 pub ty: Type,
33 pub documentation: Option<String>,
34 pub annotations: BTreeMap<String, serde_json::Value>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct Constant {
39 pub name: String,
40 pub ty: Type,
41 pub value: serde_json::Value,
42 pub documentation: Option<String>,
43}
44
45#[derive(Debug, Clone, Default, Serialize, Deserialize)]
46pub struct Metadata {
47 pub source_language: Option<String>,
48 pub source_file: Option<String>,
49 pub version: Option<String>,
50 pub generated_at: Option<String>,
51 pub custom: BTreeMap<String, serde_json::Value>,
52}
53
54impl IR {
55 pub fn new() -> Self {
56 Self {
57 modules: Vec::new(),
58 }
59 }
60
61 pub fn add_module(&mut self, module: Module) {
62 self.modules.push(module);
63 }
64
65 pub fn find_type(&self, name: &str) -> Option<&TypeDefinition> {
66 self.modules
67 .iter()
68 .flat_map(|m| &m.types)
69 .find(|t| t.name == name)
70 }
71
72 pub fn merge(mut self, other: IR) -> Self {
73 self.modules.extend(other.modules);
74 self
75 }
76}
77
78impl Default for IR {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84pub struct IRBuilder {
86 ir: IR,
87 current_module: Option<Module>,
88}
89
90impl IRBuilder {
91 pub fn new() -> Self {
92 Self {
93 ir: IR::new(),
94 current_module: None,
95 }
96 }
97
98 pub fn module(mut self, name: impl Into<String>) -> Self {
99 if let Some(module) = self.current_module.take() {
100 self.ir.add_module(module);
101 }
102 self.current_module = Some(Module {
103 name: name.into(),
104 imports: Vec::new(),
105 types: Vec::new(),
106 constants: Vec::new(),
107 metadata: Metadata::default(),
108 });
109 self
110 }
111
112 pub fn add_type(mut self, name: impl Into<String>, ty: Type) -> Self {
113 if let Some(ref mut module) = self.current_module {
114 module.types.push(TypeDefinition {
115 name: name.into(),
116 ty,
117 documentation: None,
118 annotations: BTreeMap::new(),
119 });
120 }
121 self
122 }
123
124 pub fn add_import(mut self, path: impl Into<String>) -> Self {
125 if let Some(ref mut module) = self.current_module {
126 module.imports.push(Import {
127 path: path.into(),
128 alias: None,
129 items: Vec::new(),
130 });
131 }
132 self
133 }
134
135 pub fn build(mut self) -> IR {
136 if let Some(module) = self.current_module.take() {
137 self.ir.add_module(module);
138 }
139 self.ir
140 }
141}
142
143impl Default for IRBuilder {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_ir_builder() {
155 let ir = IRBuilder::new()
156 .module("test")
157 .add_type("MyType", Type::String)
158 .add_type("MyNumber", Type::Number)
159 .build();
160
161 assert_eq!(ir.modules.len(), 1);
162 assert_eq!(ir.modules[0].name, "test");
163 assert_eq!(ir.modules[0].types.len(), 2);
164
165 let my_type = ir.find_type("MyType");
166 assert!(my_type.is_some());
167 assert_eq!(my_type.unwrap().ty, Type::String);
168 }
169}