hlang/compile.go

106 lines
1.8 KiB
Go

package main
import (
"bytes"
"context"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
"time"
"github.com/eaburns/peggy/peg"
"tulpa.dev/cadey/hlang/h"
)
var (
wat2wasmLoc string
wasmTemplateObj *template.Template
)
func init() {
loc, err := exec.LookPath("wat2wasm")
if err != nil {
panic(err)
}
wat2wasmLoc = loc
wasmTemplateObj = template.Must(template.New("h.wast").Parse(wasmTemplate))
}
// CompiledProgram is a fully parsed and compiled h program.
type CompiledProgram struct {
Source string `json:"src"`
WebAssemblyText string `json:"wat"`
Binary []byte `json:"bin"`
AST string `json:"ast"`
}
func compile(source string) (*CompiledProgram, error) {
tree, err := h.Parse(source)
if err != nil {
return nil, err
}
var sb strings.Builder
err = peg.PrettyWrite(&sb, tree)
result := CompiledProgram{
Source: source,
AST: sb.String(),
}
dir, err := ioutil.TempDir("", "h")
if err != nil {
return nil, err
}
defer os.RemoveAll(dir)
fout, err := os.Create(filepath.Join(dir, "h.wast"))
if err != nil {
return nil, err
}
buf := bytes.NewBuffer(nil)
err = wasmTemplateObj.Execute(buf, []byte(tree.Text))
if err != nil {
return nil, err
}
result.WebAssemblyText = buf.String()
_, err = fout.WriteString(result.WebAssemblyText)
if err != nil {
return nil, err
}
fname := fout.Name()
err = fout.Close()
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, wat2wasmLoc, fname, "-o", filepath.Join(dir, "h.wasm"))
cmd.Dir = dir
err = cmd.Run()
if err != nil {
return nil, err
}
data, err := ioutil.ReadFile(filepath.Join(dir, "h.wasm"))
if err != nil {
return nil, err
}
result.Binary = data
return &result, nil
}