106 lines
1.8 KiB
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
|
|
}
|