/src/target/c.rs

https://github.com/adam-mcdaniel/oakc · Rust · 162 lines · 132 code · 29 blank · 1 comment · 6 complexity · f0cfa5a3afddf75dfff65fa7431c8d3f MD5 · raw file

  1. use super::Target;
  2. use std::{
  3. env::consts::EXE_SUFFIX,
  4. fs::{remove_file, write},
  5. io::{Error, ErrorKind, Result, Write},
  6. process::{Command, Stdio},
  7. };
  8. pub struct C;
  9. impl Target for C {
  10. fn get_name(&self) -> char {
  11. 'c'
  12. }
  13. fn is_standard(&self) -> bool {
  14. true
  15. }
  16. fn std(&self) -> String {
  17. String::from(include_str!("std/std.c"))
  18. }
  19. fn core_prelude(&self) -> String {
  20. String::from(include_str!("core/core.c"))
  21. }
  22. fn core_postlude(&self) -> String {
  23. String::new()
  24. }
  25. fn begin_entry_point(&self, global_scope_size: i32, memory_size: i32) -> String {
  26. format!(
  27. "int main() {{\nmachine *vm = machine_new({}, {});\n",
  28. global_scope_size,
  29. global_scope_size + memory_size,
  30. )
  31. }
  32. fn end_entry_point(&self) -> String {
  33. String::from("\nmachine_drop(vm);\nreturn 0;\n}")
  34. }
  35. fn establish_stack_frame(&self, arg_size: i32, local_scope_size: i32) -> String {
  36. format!(
  37. "machine_establish_stack_frame(vm, {}, {});\n",
  38. arg_size, local_scope_size
  39. )
  40. }
  41. fn end_stack_frame(&self, return_size: i32, local_scope_size: i32) -> String {
  42. format!(
  43. "machine_end_stack_frame(vm, {}, {});\n",
  44. return_size, local_scope_size
  45. )
  46. }
  47. fn load_base_ptr(&self) -> String {
  48. String::from("machine_load_base_ptr(vm);\n")
  49. }
  50. fn push(&self, n: f64) -> String {
  51. format!("machine_push(vm, {});\n", n)
  52. }
  53. fn add(&self) -> String {
  54. String::from("machine_add(vm);\n")
  55. }
  56. fn subtract(&self) -> String {
  57. String::from("machine_subtract(vm);\n")
  58. }
  59. fn multiply(&self) -> String {
  60. String::from("machine_multiply(vm);\n")
  61. }
  62. fn divide(&self) -> String {
  63. String::from("machine_divide(vm);\n")
  64. }
  65. fn sign(&self) -> String {
  66. String::from("machine_sign(vm);\n")
  67. }
  68. fn allocate(&self) -> String {
  69. String::from("machine_allocate(vm);\n")
  70. }
  71. fn free(&self) -> String {
  72. String::from("machine_free(vm);\n")
  73. }
  74. fn store(&self, size: i32) -> String {
  75. format!("machine_store(vm, {});\n", size)
  76. }
  77. fn load(&self, size: i32) -> String {
  78. format!("machine_load(vm, {});\n", size)
  79. }
  80. fn fn_header(&self, name: String) -> String {
  81. format!("void {}(machine* vm);\n", name)
  82. }
  83. fn fn_definition(&self, name: String, body: String) -> String {
  84. format!("void {}(machine* vm) {{ {}}}\n", name, body)
  85. }
  86. fn call_fn(&self, name: String) -> String {
  87. format!("{}(vm);\n", name)
  88. }
  89. fn call_foreign_fn(&self, name: String) -> String {
  90. format!("{}(vm);\n", name)
  91. }
  92. fn begin_while(&self) -> String {
  93. String::from("while (machine_pop(vm)) {\n")
  94. }
  95. fn end_while(&self) -> String {
  96. String::from("}\n")
  97. }
  98. fn compile(&self, code: String) -> Result<()> {
  99. let mut child = Command::new("gcc")
  100. .arg("-O2")
  101. .args(&["-o", &format!("main{}", EXE_SUFFIX)[..]])
  102. .args(&["-x", "c", "-"])
  103. .stdin(Stdio::piped())
  104. .spawn();
  105. if let Ok(mut child) = child {
  106. match child.stdin.as_mut() {
  107. Some(stdin) => {
  108. if let Err(error) = stdin.write_all(code.as_bytes()) {
  109. return Result::Err(Error::new(
  110. ErrorKind::Other,
  111. "unable to open write to child stdin",
  112. ));
  113. }
  114. }
  115. None => {
  116. return Result::Err(Error::new(ErrorKind::Other, "unable to open child stdin"))
  117. }
  118. }
  119. match child.wait_with_output() {
  120. Ok(_) => return Result::Ok(()),
  121. Err(_) => {
  122. return Result::Err(Error::new(ErrorKind::Other, "unable to read child output"))
  123. }
  124. }
  125. } else {
  126. // child failed to execute
  127. Result::Err(Error::new(
  128. ErrorKind::Other,
  129. "unable to spawn child gcc proccess",
  130. ))
  131. }
  132. }
  133. }