1#![deny(missing_docs)]
24
25use std::fmt::{Display, Formatter};
26
27pub struct Code<'a> {
45 code: String,
46 requires: Vec<&'a str>,
47 exit: i32,
48}
49
50#[derive(Debug, Clone, Copy)]
52pub enum CArg<'a> {
53 String(&'a str),
55
56 Ident(&'a str),
58
59 Int32(i32),
61
62 Int64(i64),
64
65 Float(f32),
67
68 Double(f64),
70
71 Bool(bool),
73
74 Char(char),
76}
77
78#[derive(Debug, Clone, Copy)]
80pub enum VarTypes {
81 String,
83
84 Int32,
86
87 Int64,
89
90 Float,
92
93 Double,
95
96 Bool,
98
99 Char,
101}
102
103#[derive(Debug, Clone, Copy)]
105pub enum VarInit<'a> {
106 String(&'a str),
108
109 Ident(VarTypes, &'a str),
111
112 Int32(i32),
114
115 Int64(i64),
117
118 Float(f32),
120
121 Double(f64),
123
124 Bool(bool),
126
127 Char(char),
129
130 SizeString(usize),
132}
133
134impl Default for Code<'_> {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140impl Code<'_> {
141 pub fn new() -> Self {
156 Self {
157 code: String::new(),
158 requires: vec![],
159 exit: 0,
160 }
161 }
162
163 pub fn exit(&mut self, code: i32) {
181 self.exit = code;
182 }
183
184 pub fn include(&mut self, file: &'static str) {
203 if self.requires.contains(&file) {
204 return;
205 }
206 self.requires.push(file);
207 }
208
209 pub fn call_func(&mut self, func: &str) {
228 self.code.push_str(func);
229 self.code.push_str("();\n")
230 }
231
232 pub fn call_func_with_args(&mut self, func: &str, args: Vec<CArg>) {
251 self.code.push_str(func);
252 self.code.push('(');
253
254 for arg in args {
255 match arg {
256 CArg::String(s) => {
257 let s = s.replace("\r\n", "\\r\\n");
258 let s = s.replace('\n', "\\n");
259 let s = s.replace('\t', "\\t");
260 let s = s.replace('"', "\\\"");
261
262 self.code.push('"');
263 self.code.push_str(s.as_str());
264 self.code.push('"');
265 }
266 CArg::Ident(id) => {
267 self.code.push_str(id);
268 }
269 CArg::Int32(n) => {
270 self.code.push_str(&n.to_string());
271 }
272 CArg::Int64(n) => {
273 self.code.push_str(&n.to_string());
274 }
275 CArg::Float(n) => {
276 self.code.push_str(&n.to_string());
277 }
278 CArg::Double(n) => {
279 self.code.push_str(&n.to_string());
280 }
281 CArg::Bool(b) => {
282 self.code.push_str(&b.to_string());
283 }
284 CArg::Char(c) => {
285 self.code.push(c);
286 }
287 }
288 self.code.push(',');
289 }
290
291 if self.code.ends_with(',') {
292 self.code = self.code.strip_suffix(',').unwrap().to_string();
293 }
294
295 self.code.push_str(");\n")
296 }
297
298 pub fn new_var<S: AsRef<str>>(&mut self, name: S, value: VarInit) {
320 let name = name.as_ref();
321
322 match value {
323 VarInit::String(s) => {
324 self.code.push_str("char ");
325 self.code.push_str(name);
326
327 self.code.push_str("[]=\"");
328 self.code.push_str(s);
329 self.code.push_str("\";");
330 self.code.push('\n');
331 }
332 VarInit::Ident(ty, ident) => {
333 self.code.push_str(match ty {
334 VarTypes::String => "char ",
335 VarTypes::Int32 => "int ",
336 VarTypes::Int64 => "int ",
337 VarTypes::Float => "float ",
338 VarTypes::Double => "double ",
339 VarTypes::Bool => {
340 self.requires.push("stdbool.h");
341 "bool "
342 }
343 VarTypes::Char => "char ",
344 });
345
346 self.code.push_str(name);
347
348 if let VarTypes::String = ty {
349 self.code.push_str("[]");
350 }
351
352 self.code.push('=');
353 self.code.push_str(ident);
354 self.code.push(';');
355 self.code.push('\n');
356 }
357 VarInit::Bool(b) => {
358 self.requires.push("stdbool.h");
359
360 self.code.push_str("bool ");
361 self.code.push_str(name);
362
363 self.code.push('=');
364 self.code.push_str(&b.to_string());
365 self.code.push_str(";\n");
366 }
367 VarInit::Char(c) => {
368 self.code.push_str("char ");
369 self.code.push_str(name);
370
371 self.code.push_str("='");
372 self.code.push(c);
373 self.code.push_str("';\n");
374 }
375 VarInit::Double(f) => {
376 self.code.push_str("double ");
377 self.code.push_str(name);
378
379 self.code.push('=');
380 self.code.push_str(&f.to_string());
381 self.code.push_str(";\n");
382 }
383 VarInit::Float(f) => {
384 self.code.push_str("float ");
385 self.code.push_str(name);
386
387 self.code.push('=');
388 self.code.push_str(&f.to_string());
389 self.code.push_str(";\n");
390 }
391 VarInit::Int32(i) => {
392 self.code.push_str("int ");
393 self.code.push_str(name);
394
395 self.code.push('=');
396 self.code.push_str(&i.to_string());
397 self.code.push_str(";\n");
398 }
399 VarInit::Int64(i) => {
400 self.code.push_str("int ");
401 self.code.push_str(name);
402
403 self.code.push('=');
404 self.code.push_str(&i.to_string());
405 self.code.push_str(";\n");
406 }
407 VarInit::SizeString(size) => {
408 self.code.push_str("char ");
409 self.code.push_str(name);
410
411 self.code.push('[');
412 self.code.push_str(&size.to_string());
413 self.code.push_str("];\n");
414 }
415 }
416 }
417}
418
419impl Display for Code<'_> {
420 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
421 let mut require_string = String::new();
422
423 for require in &self.requires {
424 require_string.push_str("#include<");
425 require_string.push_str(require);
426 require_string.push_str(">\n");
427 }
428
429 writeln!(
430 f,
431 "{}int main() {{\n{}return {};\n}}",
432 require_string, self.code, self.exit
433 )
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn test_empty() {
443 let code = Code::new();
444
445 assert_eq!(code.to_string(), "int main() {\nreturn 0;\n}\n");
446 }
447
448 #[test]
449 fn test_exit_zero() {
450 let mut code = Code::new();
451
452 code.exit(0);
453
454 assert_eq!(code.to_string(), "int main() {\nreturn 0;\n}\n");
455 }
456
457 #[test]
458 fn test_exit_non_zero() {
459 let mut code = Code::new();
460
461 code.exit(1);
462
463 assert_eq!(code.to_string(), "int main() {\nreturn 1;\n}\n");
464 }
465
466 #[test]
467 fn test_multiple_exits() {
468 let mut code = Code::new();
469
470 code.exit(0);
471 code.exit(1);
472
473 assert_eq!(code.to_string(), "int main() {\nreturn 1;\n}\n");
474 }
475
476 #[test]
477 fn test_include_valid() {
478 let mut code = Code::new();
479
480 code.include("stdio.h");
481
482 assert!(code.to_string().contains("#include<stdio.h>"));
483 }
484
485 #[test]
486 fn test_func_no_args() {
487 let mut code = Code::new();
488
489 code.call_func("printf");
490
491 assert!(code.to_string().contains("printf();"));
492 }
493
494 #[test]
495 fn test_func_with_args() {
496 let mut code = Code::new();
497
498 code.call_func_with_args("printf", vec![CArg::String("Hello")]);
499
500 assert!(code.to_string().contains("printf(\"Hello\");"));
501 }
502
503 #[test]
504 fn test_variable_string() {
505 let mut code = Code::new();
506
507 code.new_var("msg", VarInit::String("Hello"));
508
509 assert!(code.to_string().contains("char msg[]=\"Hello\";"));
510 }
511
512 #[test]
513 fn test_variable_i32() {
514 let mut code = Code::new();
515
516 code.new_var("num", VarInit::Int32(i32::MAX));
517
518 assert!(code
519 .to_string()
520 .contains(format!("int num={};", i32::MAX).as_str()));
521 }
522
523 #[test]
524 fn test_variable_i64() {
525 let mut code = Code::new();
526
527 code.new_var("num", VarInit::Int64(i64::MAX));
528
529 assert!(code
530 .to_string()
531 .contains(format!("int num={};", i64::MAX).as_str()));
532 }
533
534 #[test]
535 fn test_variable_float() {
536 let mut code = Code::new();
537
538 code.new_var("num", VarInit::Float(f32::MAX));
539
540 assert!(code
541 .to_string()
542 .contains(format!("float num={};", f32::MAX).as_str()));
543 }
544
545 #[test]
546 fn test_variable_double() {
547 let mut code = Code::new();
548
549 code.new_var("num", VarInit::Double(f64::MAX));
550
551 assert!(code
552 .to_string()
553 .contains(format!("double num={};", f64::MAX).as_str()));
554 }
555
556 #[test]
557 fn test_variable_bool() {
558 let mut code = Code::new();
559
560 code.new_var("b", VarInit::Bool(true));
561
562 assert!(code.to_string().contains("bool b=true;"));
563 }
564
565 #[test]
566 fn test_variable_char() {
567 let mut code = Code::new();
568
569 code.new_var("c", VarInit::Char('c'));
570
571 assert!(code.to_string().contains("char c='c';"));
572 }
573
574 #[test]
575 fn test_variable_size_string() {
576 let mut code = Code::new();
577
578 code.new_var("msg", VarInit::SizeString(5));
579
580 assert!(code.to_string().contains("char msg[5];"));
581 }
582
583 #[test]
584 fn test_variable_ident() {
585 let mut code = Code::new();
586
587 code.new_var("s", VarInit::String("X"));
588 code.new_var("t", VarInit::Ident(VarTypes::String, "s"));
589
590 assert!(code.to_string().contains("char s[]=\"X\";\nchar t[]=s;"));
591 }
592}