1use super::parser::{
2 Statement,
3 StatementValue,
4 DefinitionType,
5 Setter,
6 Definition
7};
8use super::lexer::{
9 DefinitionType as TokenDefinitionType,
10 TypeIdentifierType as TokenTypeIdentifierType,
11 Token,
12 TokenValue,
13};
14use std::fs::File;
15use std::io::Write;
16use std::collections::HashMap;
17use std::ops::Range;
18
19#[derive(Debug)]
20pub struct CachedRawDefinition {
21 props: HashMap<String, (TokenTypeIdentifierType, TokenDefinitionType)>,
22 args: Vec<(String, TokenTypeIdentifierType, TokenDefinitionType)>,
23 inherits: Vec<String>,
24 range: Range<usize>
25}
26
27#[derive(Debug)]
28pub enum CachedDefinition {
29 Raw(CachedRawDefinition),
30 Collective(String)
31}
32
33#[derive(Debug)]
34pub struct Generator {
35 statements: Vec<Statement>,
36 definitions: HashMap<String, CachedDefinition>,
37 header: String
38}
39
40impl Generator {
41
42 fn is_valid_type(token: &Token, expected_type: &TokenTypeIdentifierType) -> Result<bool, (String, Range<usize>)> {
43 match token.value {
44 TokenValue::Bool(_) => {
45 Ok(matches!(expected_type, TokenTypeIdentifierType::Bool))
46 },
47 TokenValue::Number(_) => {
48 Ok(matches!(expected_type, TokenTypeIdentifierType::Number))
49 },
50 TokenValue::String(_) => {
51 Ok(matches!(expected_type, TokenTypeIdentifierType::String))
52 },
53 _ => Err((format!("{} is not a primitive and therefore it's type cannot be checked", token.to_string()), token.range.clone()))
54 }
55 }
56
57 fn get_prop_from_definition(&self, definition: &CachedRawDefinition, definition_name: &String, setter: &Setter) -> Result<(TokenTypeIdentifierType, TokenDefinitionType), (String, Range<usize>)> {
58 if let Some(prop) = definition.props.get(setter.name.as_str()) {
59 Ok(prop.clone())
60 } else {
61 for definition_name in &definition.inherits {
62 if let Some(parent_definition) = self.definitions.get(definition_name) {
63 if let CachedDefinition::Raw(parent_definition) = parent_definition {
64 if let Ok(result) = self.get_prop_from_definition(parent_definition, definition_name, setter) {
65 return Ok(result);
66 }
67 } else {
68 return Err((format!("cannot inherit collective definition '{}'", definition_name), definition.range.clone()))
69 }
70 } else {
71 return Err((format!("inherited undefined definition '{}'", definition_name), definition.range.clone()))
72 }
73 }
74 return Err((format!("no such property on '{}' called '{}'", definition_name, setter.name.as_str()), setter.range.clone()));
75 }
76 }
77
78 pub fn generate_from_collective(&self, children: &Vec<Statement>) -> Result<String, (String, Range<usize>)> {
79 let mut result = String::new();
80
81 for child in children {
82 match &child.value {
83 StatementValue::Object(object) => {
84 if let Some(definition) = self.definitions.get(&object.name) {
85 match definition {
86 CachedDefinition::Raw(definition) => {
87 if definition.args.len() != object.arguments.len() {
88 return Err((format!("the '{}' definition expects {} args, {} given", object.name, definition.args.len(), object.arguments.len()), child.range.clone()));
89 }
90
91 let mut inlines: Vec<(String, String)> = Vec::new();
92 let mut children: Vec<(String, String)> = Vec::new();
93
94 for i in 0..definition.args.len() {
95 let defined_arg = &definition.args[i];
96 let actual_arg = &object.arguments[i];
97
98 if let Ok(is_valid) = Generator::is_valid_type(&actual_arg, &defined_arg.1) {
100 if is_valid {
101 match defined_arg.2 {
102 TokenDefinitionType::InlineArg => {
103 inlines.push((defined_arg.0.clone(), actual_arg.value_to_string()));
104 },
105 TokenDefinitionType::ChildArg => {
106 children.push((defined_arg.0.clone(), actual_arg.value_to_string()));
107 },
108 _ => return Err((format!("expected either an InlineArg or a ChildArg, got {}", defined_arg.2.to_string()), actual_arg.range.clone()))
109 }
110 }
111 }
112 }
113
114 for setter in &object.setters {
115 let defined_prop = self.get_prop_from_definition(definition, &object.name, &setter);
116 let actual_prop = &setter.value;
117
118 match defined_prop {
119 Ok(defined_prop) => {
120 if let Ok(is_valid) = Generator::is_valid_type(&actual_prop, &defined_prop.0) {
122 if is_valid {
123 match defined_prop.1 {
124 TokenDefinitionType::InlineProp => {
125 inlines.push((setter.name.clone(), actual_prop.value_to_string()));
126 },
127 TokenDefinitionType::ChildProp => {
128 children.push((setter.name.clone(), actual_prop.value_to_string()));
129 },
130 _ => return Err((format!("expected either an InlineArg or a ChildArg, got {}", defined_prop.1.to_string()), actual_prop.range.clone()))
131 }
132 }
133 }
134 },
135 Err(err) => return Err(err)
136 }
137 }
138
139 result += "<object class=\"";
142 result += object.name.as_str();
143 result += "\"";
144
145 for inline in &inlines {
146 result += " ";
147 result += inline.0.as_str();
148 result += "=\"";
149 result += inline.1.as_str();
150 result += "\"";
151 }
152
153 result += ">\n";
154
155 for child in &children {
156 result += "<property name=\"";
157 result += child.0.as_str();
158 result += "\">";
159 result += child.1.as_str();
160 result += "</property>\n";
161 }
162
163 for child in &object.children {
164 let child = vec![child.clone()];
165 match self.generate_from_collective(&child) {
166 Ok(collective) => {
167 result += "<child>\n";
168 result += collective.as_str();
169 result += "</child>\n";
170 },
171 Err(err) => return Err(err)
172 }
173 }
174 result += "</object>\n"
175 },
176 CachedDefinition::Collective(defintion) => {
177 result += defintion.as_str();
178 }
179 }
180
181 }
182 },
183 _ => return Err((format!("found {}, expected object in collective definition", child.to_string()), child.range.clone()))
184 }
185 }
186
187
188 Ok(result)
189 }
190
191 pub fn generate_from_raw(&self, definition: &Definition, range: Range<usize>) -> Result<CachedRawDefinition, (String, Range<usize>)> {
192 let mut props: HashMap<String, (TokenTypeIdentifierType, TokenDefinitionType)> = HashMap::new();
193 let mut args: Vec<(String, TokenTypeIdentifierType, TokenDefinitionType)> = Vec::new();
194
195 let properties = &definition.children;
196 let inherits = &definition.inherits;
197
198 for property in properties {
199 if let StatementValue::Property(property_value) = &property.value {
200 match property_value.definition_type {
201 TokenDefinitionType::InlineProp | TokenDefinitionType::ChildProp => {
202 props.insert(property_value.name.clone(), (property_value.internal_type.clone(), property_value.definition_type.clone()));
203 },
204 TokenDefinitionType::InlineArg | TokenDefinitionType::ChildArg => {
205 args.push((property_value.name.clone(), property_value.internal_type.clone(), property_value.definition_type.clone()));
206 },
207 _ => return Err((format!("expected a property definition, found {}", property_value.definition_type.to_string()), property.range.clone()))
208 }
209 }
210 }
211
212 for parent_name in inherits {
213 if let Some(parent) = self.definitions.get(parent_name) {
214 if let CachedDefinition::Collective(_) = parent {
215 return Err((format!("cannot inherit collective definition '{}'", parent_name), range))
216 }
217 } else {
218 return Err((format!("'{}' cannot inherit undefined definition '{}'", definition.name, parent_name), range));
219 }
220 }
221
222 Ok(CachedRawDefinition {
223 inherits: inherits.clone(),
224 range, props, args
225 })
226 }
227
228 pub fn generate(&mut self) -> Result<(), (String, Range<usize>)> {
230 for statement in &self.statements {
231 match &statement.value {
232 StatementValue::Definition(definition) => {
233 match &definition.definition_type {
234 DefinitionType::Root(filename) => {
235 let mut file_content = String::new();
237 match self.generate_from_collective(&definition.children) {
238 Ok(collective) => {
239 file_content.push_str(collective.as_str());
240 },
241 Err(err) => return Err(err)
242 }
243 file_content.push_str("</interface>");
244
245 let mut file = File::create(format!("{}.ui", filename)).expect("failed to create output file");
246 writeln!(file, "{}", self.header).expect("failed to write to output file");
247 writeln!(file, "{}", file_content).expect("failed to write to output file");
248 },
250 DefinitionType::Collective => {
251 match self.generate_from_collective(&definition.children) {
252 Ok(collective) => {
253 self.definitions.insert(definition.name.clone(), CachedDefinition::Collective(collective));
254 },
255 Err(err) => return Err(err)
256 }
257 },
258 DefinitionType::Raw => {
259 match self.generate_from_raw(&definition, statement.range.clone()) {
260 Ok(raw) => {
261 self.definitions.insert(definition.name.clone(), CachedDefinition::Raw(raw));
262 },
263 Err(err) => return Err(err)
264 }
265 }
266 }
267 },
268 StatementValue::Header(header) => {
269 self.header.push_str(header);
270 self.header.push('\n');
271 },
272 _ => return Err((format!("this should never ever ever ever ever happen. something must be wrong with the parser if this does happen"), statement.range.clone()))
273 }
274 }
275 Ok(())
276 }
277
278 pub fn new(statements: Vec<Statement>) -> Self {
279 Generator {
280 statements,
281 definitions: HashMap::new(),
282 header: String::from("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<interface>\n")
283 }
284 }
285}
286