rpg_compiler/generator/
mod.rs

1use crate::node::{Node, NodeType, SBFunction};
2use crate::node;
3use crate::user_output::CompileError;
4use crate::node::parse_dyn_node;
5
6pub static mut MAX_CHAR: usize = 10;
7
8/// Code that allows the language to function
9const STD_CODE: &str = "\
10#![allow(unused)]
11use std::io::{stdin,stdout,Write};
12use std::fmt::{Formatter, Display};
13macro_rules! red {
14    ( $str: tt ) => ({
15        &format!(\"{}\", $str)
16    });
17    ( $other: expr) => ({
18        &format!(\"{}\", $other)
19    })
20}
21macro_rules! blue {
22    ( $str: tt ) => ({
23        &format!(\"\x1b[34m{}\x1b[0m\", $str)
24    });
25    ( $other: expr) => ({
26        &format!(\"\x1b[34m{}\x1b[0m\", $other)
27    })
28}
29macro_rules! cyan {
30    ( $str: tt ) => ({
31        &format!(\"{}\", $str)
32    });
33    ( $other: expr) => ({
34        &format!(\"{}\", $other)
35    })
36}
37macro_rules! runtime_error {
38    ($( $arg: tt)*) => ({
39        let s = format!($($arg)*);
40        eprintln!(\"{}
41{}\", cyan!(\"Runtime error\"), red!(s));
42        std::process::exit(1)
43    })
44}
45#[derive(Clone)]
46/// Either a char or a zombie
47struct Actor<'a> {
48    id: u32,
49    /// Can derive actor type using `health`
50    health: ActorHealth,
51    attack: u32,
52    items: Vec<&'a Item>,
53    confused: bool
54}
55impl<'a> Actor<'a> {
56    fn new(id: u32, h: ActorHealth, a: u32) -> Actor<'a> { Actor { id, health: h, attack: a, items: Vec::new(), confused: false } }
57    fn attacked(&mut self, val: u32, game: &mut Game) { self.health.attacked(val, self.id, game) }
58    fn heal(&mut self, val: u32) { self.health.heal(val) }
59    /// Deprecated
60    fn validate_actor(&self) -> bool { if let ActorHealth::Char(val) = self.health { return val != (0 as u32); } else { return true; } }
61    fn health(&self) -> ActorHealth {
62        if self.confused {
63            if let ActorHealth::Char(v) = self.health {
64                return ActorHealth::Char(v-1);
65            } else if let ActorHealth::Zombie(v) = self.health {
66                return ActorHealth::Zombie(v-1);
67            } else {
68                runtime_error!(\"This well never happen.\");
69            }
70        } else {
71            return self.health;
72        }
73    }
74}
75struct Merchant;
76#[derive(Clone, Copy)]
77enum ActorHealth {
78    Char(u32),
79    Zombie(i32)
80}
81impl ActorHealth {
82    fn attacked(&mut self, a: u32, actor_id: u32, game: &mut Game) {
83        match self {
84            Self::Char(val) => {
85                if *val == 0 {
86                    println!(\"Stop beating a dead corpse.\");
87                } else if *val <= a {
88                    *val = 0;
89                    let index_of_dead_actor = game.alive.iter().enumerate().find_map(|(index, act)| {
90                        if act == &actor_id {
91                            Some(index)
92                        } else {
93                            None
94                        }
95                    });
96                    game.alive.remove(index_of_dead_actor.unwrap_or_else(|| runtime_error!(\"The now deceased actor was never alive in the first place.\")));
97                } else {
98                    *val -= a;
99                }
100            }
101            Self::Zombie(val) => {
102                *val -= a as i32;
103            }
104        }
105    }
106    fn heal(&mut self, h: u32) {
107        match self {
108            Self::Char(val) => {
109                if *val == 0 {
110                    runtime_error!(\"Cannot heal a dead actor.\");
111                } else {
112                    *val += h;
113                }
114            }
115            Self::Zombie(val) => {
116                *val += h as i32;
117            }
118        }
119    }
120}
121#[derive(Clone, Copy, PartialEq)]
122enum Item {
123    /// (id, healing_value)
124    Potion(u32,u32),
125    SpellBook
126}
127impl Item {
128    fn set_val(&mut self, v: u32) {
129        match self {
130            Self::Potion(_, val) => {*val=v}
131            Self::SpellBook => {runtime_error!(\"Spellbooks don't have values.\")}
132        }
133    }
134}
135impl Display for ActorHealth {
136    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137        match self {
138            ActorHealth::Char(val) => write!(f, \"{}\", val),
139            ActorHealth::Zombie(val) => write!(f, \"{}\", val)
140        }
141    }
142}
143struct Game {
144    alive: Vec<u32>,
145    max_chars: usize
146}
147impl Game {
148    fn add_actor(&mut self, actor: u32) {
149        self.alive.push(actor);
150        if self.alive.len() > self.max_chars {
151           // Runtime error
152           let s = &format!(\"Your actors exceeded the maximum amount of actors allowed ({})\", self.max_chars);
153           eprintln!(\"{}
154{}\", cyan!(\"Runtime error\"), red!(s));
155           println!(\"{} Actors alive: {:?}\", blue!(\"HINT:\"), self.alive);
156           std::process::exit(1)
157        }
158    }
159    fn rm_actor(&mut self, id: u32) {
160        let i = self.alive.iter().enumerate().find_map(|(i,a)| {if a == &id {Some(i)}else{None}});
161        if let Some(i) = i {
162            self.alive.remove(i);
163        }
164    }
165}";
166
167/// RPG Code Generator
168pub struct Generator<'a> {
169    /// The maximum amount of characters allowed in the program
170    max_chars: usize,
171    /// The code
172    nodes: &'a Vec<Box<dyn Node + Send + Sync>>,
173}
174
175impl<'a> Generator<'a> {
176    pub fn new(nodes: &'a Vec<Box<dyn Node + Send + Sync>>) -> Self {
177        Self {
178            max_chars: unsafe{MAX_CHAR},
179            nodes,
180        }
181    }
182    
183    pub fn generate(&self) -> String {
184        format!(
185            "{}\nfn main() {{
186    let mut game = Game {{ alive: Vec::new(), max_chars: {} }};
187    {}
188}}",
189            STD_CODE,
190            self.max_chars,
191            self.generate_all().join("\n")
192        )
193    }
194    
195    fn generate_all(&self) -> Vec<String> {
196        self.nodes.iter().map(|node| self.generate_next(node)).collect::<Vec<String>>()
197    }
198    
199    fn generate_next(&self, node: &Box<dyn Node + Send + Sync>) -> String {
200        let node = &**node;
201        match node.get_type() {
202            NodeType::Char => {
203                let char: &node::Char = parse_dyn_node(node);
204                return format!(
205                    "let mut i{} = Actor::new({},ActorHealth::Char({}),{}); game.add_actor(i{}.id);",
206                    char.id,
207                    char.id,
208                    char.health,
209                    char.attack,
210                    char.id
211                );
212            }
213            NodeType::Zombie => {
214                let zombie: &node::Zombie = parse_dyn_node(node);
215                return format!(
216                    "let mut i{} = Actor::new({},ActorHealth::Zombie({}), {}); game.add_actor(i{}.id);",
217                    zombie.id,
218                    zombie.id,
219                    zombie.health,
220                    zombie.attack,
221                    zombie.id
222                );
223            }
224            NodeType::Merchant => {
225                let m: &node::Merchant = parse_dyn_node(node);
226                return format!(
227                    "let i{} = Merchant{{}};",
228                    m.id
229                );
230            }
231            NodeType::Potion => {
232                let p: &node::Potion = parse_dyn_node(node);
233                return format!(
234                    "let i{} = Item::Potion({},{});",
235                    p.id,
236                    p.id,
237                    p.value
238                )
239            }
240            NodeType::SpellBook => {
241                let sb: &node::SpellBook = parse_dyn_node(node);
242                return format!(
243                    "let i{} = Item::SpellBook;",
244                    sb.id
245                );
246            }
247            NodeType::FnBuys => {
248                let f: &node::FnBuys = parse_dyn_node(node);
249                return format!(
250                    // TODO: display name of dead actor
251                    "if game.alive.contains(&{}) {{ i{}.items.push(&i{}); }} else {{ runtime_error!(\"Cannot add an item to the inventory of a dead actor.\") }}",
252                    f.user,
253                    f.user,
254                    f.item
255                );
256            }
257            NodeType::FnAttacks => {
258                let f: &node::FnAttacks = parse_dyn_node(node);
259                return format!(
260                    "if game.alive.contains(&{}) {{ i{}.attacked(i{}.attack, &mut game); }} else {{ runtime_error!(\"A dead actor cannot attack.\") }}",
261                    f.attacker,
262                    f.attacked,
263                    f.attacker
264                );
265            }
266            NodeType::FnUses => {
267                // Only potions atm
268                let f: &node::FnUses = parse_dyn_node(node);
269                // TODO: expect to runtime error
270                return format!(
271                    "if let Item::Potion(_, heal) = i{} {{ \
272                    if game.alive.contains(&{}) {{ \
273                    i{}.heal(heal);\
274                    let item_index = i{}.items.iter().enumerate().find_map(|(i, p)| {{
275                        let mut _val = None;
276                        if let Item::Potion(id,val) = p {{if &{} == id {{_val = Some(i);}} else {{_val = None;}} }}
277                        _val
278                    }});
279                    i{}.items.remove(item_index.expect(\"The actor does not own the potion it is trying to use.\"));
280                    }}\
281                    }}",
282                    f.item,
283                    f.user,
284                    f.user,
285                    f.user,
286                    f.item,
287                    f.user
288                );
289            }
290            NodeType::FnShouts => {
291                let expr: &node::FnShouts = parse_dyn_node(node);
292                let user = expr.user;
293                return format!(
294                    "if !game.alive.contains(&{user}) {{ runtime_error!(\"Dead actors can't shout.\") }} \
295                    else {{ println!(\"{{}}\", i{user}.clone().health()); }}",
296                );
297            }
298            NodeType::FnShoutsSpeak => {
299                let expr: &node::FnShoutsSpeak = parse_dyn_node(node);
300                let item = expr.spell_book;
301                let usr = expr.user;
302                return format!(
303                    "if !i{usr}.items.contains(&&i{item}) {{ runtime_error!(\"The spell cannot be called, because the caster doesn't own a spellbook.\") }};\
304                    if !game.alive.contains(&{usr}) {{ runtime_error!(\"Dead actors can't shout.\") }} else if let ActorHealth::Char(val) = i{usr}.health() {{ println!(\"{{}}\", (val as u8) as char); }} else {{ runtime_error!(\"Wrong type, only characters can shout speak.\") }}",
305                );
306            }
307            NodeType::FnWhispers => {
308                let expr: &node::FnWhispers = parse_dyn_node(node);
309                return format!(
310                    "if !i{}.validate_actor() {{ runtime_error!(\"Dead actors can't shout.\") }} print!(\"{{}}\", i{}.health());",
311                    expr.user,
312                    expr.user
313                );
314            }
315            NodeType::FnWhispersSpeak => {
316                let expr: &node::FnWhispersSpeak = parse_dyn_node(node);
317                let item = expr.spell_book;
318                let usr = expr.user;
319                return format!(
320                    "if !i{usr}.items.contains(&&i{item}) {{ runtime_error!(\"The spell cannot be called, because the caster doesn't own a spellbook.\") }}; \
321                    if !i{usr}.validate_actor() {{ runtime_error!(\"Dead actors can't shout.\") }} \
322                    else if let ActorHealth::Char(val) = i{usr}.health() {{ print!(\"{{}}\", (val as u8) as char); }} \
323                    else {{ runtime_error!(\"Wrong type, only characters can whisper speak.\") }}",
324                );
325            }
326            NodeType::FnUsesCasting => {
327                let f: &node::FnUsesCasting = parse_dyn_node(node);
328                let usr = f.user;
329                let item = f.spell_book;
330                let mut return_s = format!("if !i{usr}.items.contains(&&i{item}) {{ runtime_error!(\"The spell cannot be called, because the caster doesn't own a spellbook.\") }};");
331                match f.function {
332                    SBFunction::UnZombify => {
333                        let id = f.parameter.expect_compile_error("Un_zombify called without zombie parameter.");
334                        return_s.push_str(&format!(
335                            "let i{id} = if let ActorHealth::Zombie(h) = i{id}.health {{\
336                            if h <= 0 {{ game.rm_actor({id}); i{id} }} else {{ Actor::new({id}, ActorHealth::Char(h as u32), i{id}.attack) }}\
337                            }} else {{runtime_error!(\"Tried to call `un_zombify` on a non-zombie.\")}};"
338                        ));
339                    }
340                    SBFunction::Confuse => {
341                        let id = f.parameter.expect_compile_error("Confuse called without parameter.");
342                        return_s.push_str(&format!(
343                            "i{id}.confused = true;"
344                        ));
345                    }
346                    SBFunction::GodSpeech => {
347                        //  TODO: expect to runtime error
348                        let user = f.user;
349                        return_s.push_str(&format!(
350                            "{{\
351                            let mut s = String::new();
352                            let _ = stdout().flush();
353                            stdin().read_line(&mut s).expect(\"Input invalid.\");
354                            if let Some('\\n')=s.chars().next_back() {{
355                                s.pop();
356                            }}
357                            if let Some('\\r')=s.chars().next_back() {{
358                                s.pop();
359                            }}
360                            match i{user}.health {{
361                                ActorHealth::Char(_) => {{i{user}.health = ActorHealth::Char(s.parse::<u32>().expect(\"Invalid input\"))}}
362                                ActorHealth::Zombie(_) => {{i{user}.health = ActorHealth::Zombie(s.parse::<i32>().expect(\"Invalid input\"))}}
363                            }}
364                            }}"
365                        ));
366                    }
367                    SBFunction::TimeWarp => {
368                        let body: Vec<String> = if f.body.is_some() {
369                            f.body.as_ref().expect_compile_error("Unkown error: expected body, but was empty.")
370                                .body.iter()
371                                .map(|node| {
372                                    self.generate_next(node)
373                                }
374                                ).collect::<Vec<String>>()
375                        } else {
376                            Vec::new()
377                        };
378                        let consumed = f.parameter.expect_compile_error("Expected a parameter for spell `time_warp`.");
379                        return_s.push_str(&format!(
380                            /**/
381                            "{{
382                                let mut loop_times = match &mut i{consumed}.health {{
383                                    ActorHealth::Char(val) => {{
384                                        *val
385                                    }}
386                                    ActorHealth::Zombie(val) => {{runtime_error!(\"Zombies don't like loops.\")}}
387                                }};
388                                while loop_times != 0 {{
389                                    {}
390                                    i{consumed}.attacked(1, &mut game);
391                                    
392                                    loop_times =  match &mut i{consumed}.health {{
393                                        ActorHealth::Char(val) => {{
394                                            *val
395                                        }}
396                                        ActorHealth::Zombie(val) => {{runtime_error!(\"Zombies don't like loops.\")}}
397                                    }};
398                                }}
399                            }}",
400                            body.join("\n")
401                            // NOTE: actors are consumed at the end of an iteration
402                        ));
403                    }
404                    SBFunction::Shift => {
405                        let user = f.user;
406                        return_s.push_str(&format!("\
407                        {{ let health = i{user}.attack;
408                        if let ActorHealth::Char(attack) = i{user}.health {{
409                            i{user}.attack = attack;
410                            i{user}.health = ActorHealth::Char(health);
411                        }}
412                        }}"));
413                    }
414                    SBFunction::CreatePot => {
415                        let user = f.user;
416                        let potion = f.parameter.unwrap();
417                        // return_s.push_str(&format!(
418                        //     "let i{potion} = Item::Potion({potion}, if let Some(h) = i{user}.health {{\
419                        //     h}} else {{runtime_error!(\"Actor does not exist.\"}});"
420                        // ))
421                        return_s.push_str(&format!(
422                            "let potion_index = i{user}.items.iter().enumerate().find_map(|(i,item)| if item == &&i{potion} {{Some(i)}} else {{None}}); \
423                            i{user}.items.remove(potion_index.unwrap());\
424                            let health: u32 = if let ActorHealth::Char(h) = i{user}.health {{
425                                h
426                            }} else {{ runtime_error!(\"Only actors can make potions.\") }};
427                            let i{potion} = Item::Potion({potion}, health);
428                            i{user}.items.push(&i{potion});"
429                            //if let ActorHealth::Char(h) = i{user}.health {{\
430                            // i{potion}.set_val(h);\
431                            // }}"
432                        ))
433                    }
434                }
435                return return_s;
436            }
437            NodeType::FnBody => {}
438        }
439        unimplemented!("That function has not been implemented.")
440    }
441}