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
use super::Target;
use std::{
    fs::{remove_file, write},
    io::{Error, ErrorKind, Result},
    process::Command,
};

pub struct Go;
impl Target for Go {
    fn get_name(&self) -> char {
        'g'
    }

    fn std(&self) -> String {
        String::from(include_str!("std/std.go"))
    }

    fn core_prelude(&self) -> String {
        String::from(include_str!("core/core.go"))
    }

    fn core_postlude(&self) -> String {
        String::new()
    }

    fn begin_entry_point(&self, global_scope_size: i32, memory_size: i32) -> String {
        format!(
            "func main() {{\nvm := machine_new({}, {})\n",
            global_scope_size,
            global_scope_size + memory_size,
        )
    }

    fn end_entry_point(&self) -> String {
        String::from("\nvm.drop()\n}")
    }

    fn establish_stack_frame(&self, arg_size: i32, local_scope_size: i32) -> String {
        format!(
            "vm.establish_stack_frame({}, {})\n",
            arg_size, local_scope_size
        )
    }

    fn end_stack_frame(&self, return_size: i32, local_scope_size: i32) -> String {
        format!(
            "vm.end_stack_frame({}, {})\n",
            return_size, local_scope_size
        )
    }

    fn load_base_ptr(&self) -> String {
        String::from("vm.load_base_ptr()\n")
    }

    fn push(&self, n: f64) -> String {
        format!("vm.push({})\n", n)
    }

    fn add(&self) -> String {
        String::from("vm.add()\n")
    }

    fn subtract(&self) -> String {
        String::from("vm.subtract()\n")
    }

    fn multiply(&self) -> String {
        String::from("vm.multiply()\n")
    }

    fn divide(&self) -> String {
        String::from("vm.divide()\n")
    }

    fn sign(&self) -> String {
        String::from("vm.sign()\n")
    }

    fn allocate(&self) -> String {
        String::from("vm.allocate()\n")
    }

    fn free(&self) -> String {
        String::from("vm.free()\n")
    }

    fn store(&self, size: i32) -> String {
        format!("vm.store({})\n", size)
    }

    fn load(&self, size: i32) -> String {
        format!("vm.load({})\n", size)
    }

    fn fn_header(&self, name: String) -> String {
        String::new()
    }

    fn fn_definition(&self, name: String, body: String) -> String {
        format!("\n\nfunc {}(vm *machine) {{\n{}\n}}\n", name, body)
    }

    fn call_fn(&self, name: String) -> String {
        format!("{}(vm);\n", name)
    }

    fn call_foreign_fn(&self, name: String) -> String {
        format!("{}(vm);\n", name)
    }

    fn begin_while(&self) -> String {
        String::from("for vm.pop() != 0.0 {\n")
    }

    fn end_while(&self) -> String {
        String::from("}\n")
    }

    fn compile(&self, code: String) -> Result<()> {
        if let Ok(_) = write("main.go", code) {
            if let Ok(_) = Command::new("go").arg("build").arg("main.go").output() {
                if let Ok(_) = remove_file("main.go") {
                    return Result::Ok(());
                }
            }
        }
        Result::Err(Error::new(
            ErrorKind::Other,
            "could not compile output golang code. is golang installed?",
        ))
    }
}