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
8const 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!(\"[31m{}[0m\", $str)
16 });
17 ( $other: expr) => ({
18 &format!(\"[31m{}[0m\", $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!(\"[36m{}[0m\", $str)
32 });
33 ( $other: expr) => ({
34 &format!(\"[36m{}[0m\", $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
167pub struct Generator<'a> {
169 max_chars: usize,
171 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 "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 let f: &node::FnUses = parse_dyn_node(node);
269 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 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 "{{
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 ));
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!(
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 ))
433 }
434 }
435 return return_s;
436 }
437 NodeType::FnBody => {}
438 }
439 unimplemented!("That function has not been implemented.")
440 }
441}