diff options
| author | Christine Dodrill <me@christine.website> | 2019-06-26 02:19:50 +0000 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2019-06-26 02:19:50 +0000 |
| commit | bfea637d7698f5d9b1bcf5fbc43fc1f7ae245fa8 (patch) | |
| tree | 819d090f6953e9b078f685e76a0001ecb8560138 | |
| parent | 96a073ecddf7eee051050347a09786dc38b3a8ac (diff) | |
| download | x-bfea637d7698f5d9b1bcf5fbc43fc1f7ae245fa8.tar.xz x-bfea637d7698f5d9b1bcf5fbc43fc1f7ae245fa8.zip | |
cmd/h: simplify, add http playground API route
| -rw-r--r-- | cmd/h/http.go | 55 | ||||
| -rw-r--r-- | cmd/h/main.go | 83 | ||||
| -rw-r--r-- | cmd/h/run.go | 19 |
3 files changed, 138 insertions, 19 deletions
diff --git a/cmd/h/http.go b/cmd/h/http.go new file mode 100644 index 0000000..696cf78 --- /dev/null +++ b/cmd/h/http.go @@ -0,0 +1,55 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/http" +) + +var ( + maxBytes = flag.Int64("max-playground-bytes", 75, "how many bytes of data should users be allowed to post to the playground?") +) + +func doHTTP() error { + http.HandleFunc("/api/playground", runPlayground) + + return http.ListenAndServe(":"+*port, nil) +} + +func runPlayground(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.NotFound(w, r) + return + } + + rc := http.MaxBytesReader(w, r.Body, *maxBytes) + defer rc.Close() + + data, err := ioutil.ReadAll(rc) + if err != nil { + http.Error(w, "too many bytes sent", http.StatusBadRequest) + return + } + + comp, err := compile(string(data)) + if err != nil { + http.Error(w, fmt.Sprintf("compilation error: %v", err), http.StatusBadRequest) + return + } + + er, err := run(comp.Binary) + if err != nil { + http.Error(w, fmt.Sprintf("runtime error: %v", err), http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(struct { + Program *CompiledProgram `json:"prog"` + Results *ExecResult `json:"res"` + }{ + Program: comp, + Results: er, + }) +} diff --git a/cmd/h/main.go b/cmd/h/main.go index f7e064e..cdfbf99 100644 --- a/cmd/h/main.go +++ b/cmd/h/main.go @@ -3,28 +3,49 @@ package main import ( "flag" "fmt" + "io/ioutil" "log" + "os" "within.website/x/internal" ) var ( - program = flag.String("p", "h", "h program to compile/run") + program = flag.String("p", "", "h program to compile/run") + outFname = flag.String("o", "", "if specified, write the webassembly binary created by -p here") + watFname = flag.String("o-wat", "", "if specified, write the uncompiled webassembly created by -p here") + port = flag.String("port", "", "HTTP port to listen on") + writeTao = flag.Bool("koan", false, "if true, print the h koan and then exit") ) -func main() { - internal.HandleStartup() +const koan = `And Jesus said unto the theologians, "Who do you say that I am?". + +They replied: "You are the eschatological manifestation of the ground of our +being, the kerygma of which we find the ultimate meaning in our interpersonal +relationships." + +And Jesus said "...What?" + +Some time passed and one of them spoke "h". + +Jesus was enlightened.` + +func tao() { + fmt.Println(koan) + os.Exit(0) +} +func oneOff() error { log.Println("compiling...") comp, err := compile(*program) if err != nil { - panic(err) + return err } log.Println("running...") - er, err := run(*comp) + er, err := run(comp.Binary) if err != nil { - panic(err) + return err } log.Println("success!") @@ -32,7 +53,53 @@ func main() { log.Printf("gas used:\t%d", er.GasUsed) log.Printf("exec time:\t%s", er.ExecTime) log.Println("output:") - fmt.Println(er.Output) + fmt.Print(er.Output) + + if *outFname != "" { + err := ioutil.WriteFile(*outFname, comp.Binary, 0666) + if err != nil { + return err + } + + log.Printf("wrote %d bytes to %s", len(comp.Binary), *outFname) + } + + if *watFname != "" { + err := ioutil.WriteFile(*watFname, []byte(comp.WebAssemblyText), 0666) + if err != nil { + return err + } + + log.Printf("write %d bytes of source to %s", len(comp.WebAssemblyText), *watFname) + } + + return nil +} + +func main() { + internal.HandleStartup() + + if *writeTao { + tao() + } + + if *program != "" { + err := oneOff() + if err != nil { + panic(err) + } + + return + } + + if *port != "" { + err := doHTTP() + if err != nil { + panic(err) + } + + return + } } const wasmTemplate = `(module @@ -55,5 +122,5 @@ const wasmTemplate = `(module {{ end -}} (call $h (get_local 0)) ) - (export "main" (func $h_main)) + (export "h" (func $h_main)) )` diff --git a/cmd/h/run.go b/cmd/h/run.go index d07e51f..fb55bb7 100644 --- a/cmd/h/run.go +++ b/cmd/h/run.go @@ -9,7 +9,6 @@ import ( ) type Process struct { - Source CompiledProgram Output []byte } @@ -40,26 +39,24 @@ func (p *Process) ResolveFunc(module, field string) exec.FunctionImport { } type ExecResult struct { - Output string - GasUsed uint64 - ExecTime time.Duration + Output string `json:"out"` + GasUsed uint64 `json:"gas"` + ExecTime time.Duration `json:"exec_duration"` } -func run(cp CompiledProgram) (*ExecResult, error) { - p := &Process{ - Source: cp, - } +func run(bin []byte) (*ExecResult, error) { + p := &Process{} var cfg exec.VMConfig gp := &compiler.SimpleGasPolicy{GasPerInstruction: 1} - vm, err := exec.NewVirtualMachine(cp.Binary, cfg, p, gp) + vm, err := exec.NewVirtualMachine(bin, cfg, p, gp) if err != nil { return nil, err } - mainFunc, ok := vm.GetFunctionExport("main") + mainFunc, ok := vm.GetFunctionExport("h") if !ok { - return nil, errors.New("impossible state: no main function exposed") + return nil, errors.New("impossible state: no h function exposed") } t0 := time.Now() |
