156 lines
3.2 KiB
Go
156 lines
3.2 KiB
Go
//go:build wasm && go1.24
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"syscall/js"
|
|
|
|
"neemek.com/anglais/core"
|
|
)
|
|
|
|
type JsResolver struct {
|
|
jsResolver js.Value
|
|
}
|
|
|
|
func (r *JsResolver) IsSame(a, b string) bool {
|
|
return a == b
|
|
}
|
|
|
|
func (r *JsResolver) Resolve(_, name string) (*core.ImportResult, error) {
|
|
jsv := r.jsResolver.Invoke(name)
|
|
|
|
if jsv.Type() == js.TypeUndefined {
|
|
return nil, errors.New("cannot find import with name " + name)
|
|
}
|
|
|
|
if jsv.Type() != js.TypeString {
|
|
return nil, errors.New("invalid value for source: " + jsv.String())
|
|
}
|
|
|
|
return &core.ImportResult{
|
|
Source: jsv.String(),
|
|
Path: name,
|
|
}, nil
|
|
}
|
|
|
|
func jsError(err error) interface{} {
|
|
return jsErrorOfString(err.Error())
|
|
}
|
|
|
|
func jsErrorOfString(err string) interface{} {
|
|
errorConstructor := js.Global().Get("Error")
|
|
errorObject := errorConstructor.New(err)
|
|
|
|
return errorObject
|
|
}
|
|
|
|
func run(_ js.Value, args []js.Value) interface{} {
|
|
source := args[0].String()
|
|
outputHandler := args[1]
|
|
errorHandler := args[2]
|
|
resolver := args[3]
|
|
log.Printf("got source: %s", source)
|
|
|
|
lexer := core.NewLexer(source)
|
|
tokens, err := lexer.Tokenize()
|
|
|
|
if err != nil {
|
|
return jsError(err)
|
|
}
|
|
|
|
log.Printf("got tokens: %v", tokens)
|
|
|
|
parser := core.NewParser(source, []string{}, tokens)
|
|
|
|
tree, err := parser.Parse(source)
|
|
|
|
if err != nil {
|
|
var e core.FormatedError
|
|
if errors.As(err, &e) {
|
|
errorHandler.Invoke(e.Format())
|
|
return nil
|
|
}
|
|
errorHandler.Invoke(err.Error())
|
|
return nil
|
|
}
|
|
|
|
log.Printf("Parsed tree: %s", tree.String())
|
|
|
|
compiler := core.NewCompiler([]rune(source))
|
|
|
|
log.Println("Set imports resolver")
|
|
|
|
compiler.SetImportsResolver(&JsResolver{
|
|
resolver,
|
|
})
|
|
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
log.Printf("panic recovered: %v", err)
|
|
}
|
|
}()
|
|
|
|
_, err = compiler.Compile(tree)
|
|
if err != nil {
|
|
var e core.CompilerError
|
|
if errors.As(err, &e) {
|
|
errorHandler.Invoke(e.Format())
|
|
return nil
|
|
}
|
|
|
|
errorHandler.Invoke(err.Error())
|
|
return nil
|
|
}
|
|
|
|
log.Printf("Compiled tree (into %v instructions)", len(compiler.Chunk.Bytecode))
|
|
|
|
vm := core.NewVM(compiler.Chunk, 256, 256)
|
|
|
|
// overwrite output
|
|
vm.SetGlobal("write", &core.BuiltinFunctionValue{
|
|
Name: "write",
|
|
Signature: &core.FunctionSignature{
|
|
In: []core.TypeSignature{&core.StringSignature{}},
|
|
Out: &core.NilSignature{},
|
|
},
|
|
F: func(vm *core.VM, this core.Value, args []core.Value) (core.Value, error) {
|
|
s := args[0].String()
|
|
log.Printf("Writing value: %s", s)
|
|
outputHandler.Invoke(js.ValueOf(s + "\n"))
|
|
return nil, nil
|
|
},
|
|
})
|
|
vm.SetGlobal("print", &core.BuiltinFunctionValue{
|
|
Name: "print",
|
|
Signature: &core.FunctionSignature{
|
|
In: []core.TypeSignature{&core.StringSignature{}},
|
|
Out: &core.NilSignature{},
|
|
},
|
|
F: func(vm *core.VM, this core.Value, args []core.Value) (core.Value, error) {
|
|
s := args[0].String()
|
|
log.Printf("Printing value: %s", s)
|
|
outputHandler.Invoke(js.ValueOf(s))
|
|
return nil, nil
|
|
},
|
|
})
|
|
|
|
for vm.Next() {
|
|
}
|
|
|
|
log.Println("Finished executing")
|
|
|
|
return js.Null()
|
|
}
|
|
|
|
func main() {
|
|
log.Println("Initializing Anglais WASM module")
|
|
|
|
js.Global().Set("run", js.FuncOf(run))
|
|
|
|
log.Println("Initialized Anglais WASM module")
|
|
|
|
// keep alive so run func can be used
|
|
select {}
|
|
}
|