1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
use crate::parser;
use crate::utils;

const HEADER: &str = r#"
use fltk::browser::*;
use fltk::button::*;
use fltk::dialog::*;
use fltk::frame::*;
use fltk::group::*;
use fltk::image::*;
use fltk::input::*;
use fltk::menu::*;
use fltk::misc::*;
use fltk::output::*;
use fltk::prelude::*;
use fltk::table::*;
use fltk::text::*;
use fltk::tree::*;
use fltk::valuator::*;
use fltk::widget::*;
use fltk::window::*;"#;

/// Generate the output Rust string/file 
pub fn generate(ast: &[parser::Token]) -> String {
    let mut s = "".to_string();
    let mut ctor = "".to_string();
    let mut imp = "".to_string();
    let mut subs = vec![];
    let mut last_scope = None;
    let mut last_ast = parser::TokenType::Global;
    let mut gparent: Vec<String> = vec![];
    for elem in ast {
        use parser::TokenType::*;
        match &elem.typ {
            Class => {
                s += "#[derive(Debug, Clone, Default)]\n";
                s += "pub struct ";
                s += &elem.ident;
                s += " {\n";
                imp += "impl ";
                imp += &elem.ident;
                imp += " {\n";
            }
            Function => {
                imp += "    pub fn ";
                imp += &elem.ident;
                if !elem.ident.contains("-> Self") {
                    imp += " -> Self";
                }
                imp += " {\n";
                ctor += "\tSelf { ";
            }
            Member(t, is_parent, props) => {
                if t != "MenuItem" && t != "Submenu" && !elem.ident.contains("fl2rust_widget_") {
                    s += &format!("    pub {}: {},\n", &elem.ident, t);
                    ctor += &elem.ident;
                    ctor += ", ";
                }
                let xywh = props.iter().position(|x| x == "xywh").unwrap();
                let label = props.iter().position(|x| x == "label");
                let typ = props.iter().position(|x| x == "type");
                if !is_parent {
                    if t != "MenuItem" {
                        imp += &format!(
                            "\tlet mut {} = {}::new({}, \"{}\");\n",
                            &elem.ident,
                            &t,
                            utils::unbracket(&props[xywh + 1].replace(" ", ", ")),
                            if let Some(l) = label {
                                utils::unbracket(&props[l + 1])
                            } else {
                                ""
                            }
                        );
                    }
                } else if t != "Submenu" {
                    imp += &format!(
                        "\tlet mut {0} = {1}::new({2}, \"{3}\");\n\t{0}.end();\n",
                        &elem.ident,
                        &t,
                        utils::unbracket(&props[xywh + 1].replace(" ", ", ")),
                        if let Some(l) = label {
                            utils::unbracket(&props[l + 1])
                        } else {
                            ""
                        }
                    );
                }
                for i in 0..props.len() {
                    match props[i].as_str() {
                        "visible" => {
                            imp += &format!("\t{}.show();\n", &elem.ident,);
                        }
                        "color" => {
                            imp += &format!(
                                "\t{}.set_color(Color::by_index({}));\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "selection_color" => {
                            imp += &format!(
                                "\t{}.set_selection_color(Color::by_index({}));\n",
                                &elem.ident,
                                utils::global_to_pascal(utils::unbracket(&props[i + 1]))
                            );
                        }
                        "labelsize" => {
                            imp += &format!(
                                "\t{}.set_label_size({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "textsize" => {
                            imp += &format!(
                                "\t{}.set_text_size({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "labeltype" => {
                            imp += &format!(
                                "\t{}.set_label_type(LabelType::{});\n",
                                &elem.ident,
                                utils::global_to_pascal(utils::unbracket(&props[i + 1]))
                            );
                        }
                        "labelcolor" => {
                            imp += &format!(
                                "\t{}.set_label_color(Color::by_index({}));\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "labelfont" => {
                            imp += &format!(
                                "\t{}.set_label_font(Font::by_index({}));\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "textfont" => {
                            imp += &format!(
                                "\t{}.set_text_font(Font::by_index({}));\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "box" => {
                            imp += &format!(
                                "\t{}.set_frame(FrameType::{});\n",
                                &elem.ident,
                                utils::global_to_pascal(utils::unbracket(&props[i + 1]))
                            );
                        }
                        "down_box" => {
                            imp += &format!(
                                "\t{}.set_down_frame(FrameType::{});\n",
                                &elem.ident,
                                utils::global_to_pascal(utils::unbracket(&props[i + 1]))
                            );
                        }
                        "when" => {
                            imp += &format!(
                                "\t{}.set_trigger(unsafe {{std::mem::transmute({})}});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "tooltip" => {
                            imp += &format!(
                                "\t{}.set_tooltip(\"{}\");\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "maximum" => {
                            imp += &format!(
                                "\t{}.set_maximum({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "minimum" => {
                            imp += &format!(
                                "\t{}.set_minimum({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "step" => {
                            imp += &format!(
                                "\t{}.set_step({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "value" => {
                            imp += &format!(
                                "\t{}.set_value(\"{}\");\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "type" => {
                            if props[i + 1] != "Double" && t != "MenuItem" && t != "Submenu" {
                                imp += &format!(
                                    "\t{}.set_type({}Type::{});\n",
                                    &elem.ident,
                                    utils::fix_type(t),
                                    utils::global_to_pascal(utils::unbracket(&props[i + 1]))
                                );
                            }
                        }
                        "align" => {
                            imp += &format!(
                                "\t{}.set_align(unsafe {{std::mem::transmute({})}});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "shortcut" => {
                            imp += &format!(
                                "\t{}.set_shortcut(unsafe {{std::mem::transmute({})}});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1])
                            );
                        }
                        "image" => {
                            imp += &format!(
                                "\t{0}.set_image(Some(SharedImage::load(\"{1}\").expect(\"Could not find image: {1}\")));\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1]),
                            );
                        }
                        "hide" => {
                            imp += &format!("\t{}.hide();\n", &elem.ident,);
                        }
                        "modal" => {
                            imp += &format!("\t{}.make_modal(true);\n", &elem.ident,);
                        }
                        "resizable" => {
                            if *is_parent {
                                imp += &format!("\t{}.make_resizable(true);\n", &elem.ident,);
                            }
                        }
                        "size_range" => {
                            imp += &format!(
                                "\t{}.size_range({});\n",
                                &elem.ident,
                                utils::unbracket(&props[i + 1].replace(" ", ", "))
                            );
                        }
                        _ => (),
                    }
                }
                if !gparent.is_empty() && !gparent.last().unwrap().contains("Function") {
                    if t != "MenuItem" && t != "Submenu" {
                        let parent = gparent.last().unwrap().clone();
                        let parent: Vec<&str> = parent.split_whitespace().collect();
                        let parent = parent[1];
                        imp += &format!("\t{}.add(&{});\n", parent, &elem.ident);
                        if props.contains(&"resizable".to_string()) {
                            imp += &format!("\t{}.resizable(&{});\n", parent, &elem.ident);
                        }
                        if props.contains(&"hotspot".to_string()) {
                            imp += &format!("\t{}.hotspot(&{});\n", parent, &elem.ident);
                        }
                    } else if t == "MenuItem" {
                        let mut menu_parent = "".to_string();
                        for p in gparent.iter().rev() {
                            if !p.contains("Submenu") {
                                menu_parent = p.clone();
                                break;
                            }
                        }
                        let parent: Vec<&str> = menu_parent.split_whitespace().collect();
                        let parent = parent[1];
                        imp += &format!(
                            "\t{}.add(\"{}{}\", Shortcut::None, MenuFlag::{}, || {{}});\n",
                            parent,
                            utils::vec2menu(&subs),
                            if let Some(l) = label {
                                utils::unbracket(&props[l + 1])
                            } else {
                                ""
                            },
                            if let Some(ty) = typ {
                                &props[ty + 1]
                            } else {
                                "Normal"
                            }
                        );
                    } else if t == "Submenu" {
                        subs.push(&elem.ident);
                    } else {
                        //
                    }
                }
            }
            Scope(op, p) => {
                if !*op {
                    if let Some(p) = p.last() {
                        if p.contains("Function") {
                            ctor += "..Default::default() }";
                            imp += &ctor;
                            imp += "\n    }\n";
                            ctor.clear();
                        }
                        if let parser::TokenType::Scope(false, _) = last_ast {
                            if let Some(last_scope) = last_scope {
                                if let parser::TokenType::Scope(false, last_parent) = last_scope
                                {
                                    if let Some(l) = last_parent.last() {
                                        if l.contains("Submenu") || l.contains("Fl_") {
                                            subs.pop();
                                            gparent.pop();
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        imp += "}\n\n";
                        s += "}\n\n";
                    }
                    last_scope = Some(parser::TokenType::Scope(false, p.clone()));
                } else {
                    gparent = p.clone();
                }
            }
            _ => (),
        }
        last_ast = elem.typ.clone();
    }
    format!("{}\n\n{}\n{}\n", HEADER, s, imp)
}