diff --git a/serve b/serve new file mode 100755 index 0000000..8f2b81d --- /dev/null +++ b/serve @@ -0,0 +1,2 @@ +cd ./wasm +npx serve \ No newline at end of file diff --git a/src/built-ins.go b/src/built-ins.go index df2aa14..cf2eee7 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -8,6 +8,7 @@ func makeGlobal(allowDocument bool) ArObject { if allowDocument { vars.obj["document"] = ArDocument } + vars.obj["js"] = ArJS vars.obj["term"] = ArTerm vars.obj["number"] = builtinFunc{"number", ArgonNumber} vars.obj["string"] = builtinFunc{"string", ArgonString} diff --git a/src/wasm.go b/src/wasm.go index 0d59bdd..0092945 100644 --- a/src/wasm.go +++ b/src/wasm.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "strings" "syscall/js" ) @@ -34,6 +35,7 @@ func argonToJsValid(argon any) any { } func wasmRun(code string, allowDocument bool) (any, ArErr) { + JSclearTimers() initRandom() global := makeGlobal(allowDocument) lines := strings.Split(code, "\n") @@ -71,3 +73,122 @@ func wasmRun(code string, allowDocument bool) (any, ArErr) { }) return ThrowOnNonLoop(run(translated, stack{global, localvars, local})) } + +var IntervalList = []int{} +var TimeoutList = []int{} + +func JSclearTimers() { + for _, v := range IntervalList { + js.Global().Call("clearInterval", v) + } + for _, v := range TimeoutList { + js.Global().Call("clearTimeout", v) + } +} + +var ArJS = Map(anymap{ + "setTimeout": builtinFunc{"setTimeout", func(args ...any) (any, ArErr) { + if len(args) > 2 || len(args) < 1 { + return nil, ArErr{"TypeError", "Expected 1 or 2 argument, got " + fmt.Sprint(len(args)), 0, "", "", true} + } + if typeof(args[0]) != "function" { + return nil, ArErr{"TypeError", "Expected function, got " + typeof(args[0]), 0, "", "", true} + } + var ms int64 = 0 + if len(args) == 2 { + if typeof(args[1]) != "number" { + return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[1]), 0, "", "", true} + } + if !args[1].(number).IsInt() { + return nil, ArErr{"TypeError", "Expected integer, got float", 0, "", "", true} + } + ms = args[1].(number).Num().Int64() + } + f := js.FuncOf(func(this js.Value, a []js.Value) interface{} { + runCall( + call{ + callable: args[0], + args: []any{}, + }, + stack{}, + 0, + ) + return nil + }) + n := js.Global().Call("setTimeout", f, ms).Int() + TimeoutList = append(TimeoutList, n) + return newNumber().SetInt64(int64(n)), ArErr{} + }}, + "setInterval": builtinFunc{"setInterval", func(args ...any) (any, ArErr) { + if len(args) > 2 || len(args) < 1 { + return nil, ArErr{"TypeError", "Expected 1 or 2 argument, got " + fmt.Sprint(len(args)), 0, "", "", true} + } + if typeof(args[0]) != "function" { + return nil, ArErr{"TypeError", "Expected function, got " + typeof(args[0]), 0, "", "", true} + } + var ms int64 = 0 + if len(args) == 2 { + if typeof(args[1]) != "number" { + return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[1]), 0, "", "", true} + } + if !args[1].(number).IsInt() { + return nil, ArErr{"TypeError", "Expected integer, got float", 0, "", "", true} + } + ms = args[1].(number).Num().Int64() + } + f := js.FuncOf(func(this js.Value, a []js.Value) interface{} { + runCall( + call{ + callable: args[0], + args: []any{}, + }, + stack{}, + 0, + ) + return nil + }) + n := js.Global().Call("setInterval", f, ms).Int() + IntervalList = append(IntervalList, n) + return newNumber().SetInt64(int64(n)), ArErr{} + }}, + "clearTimeout": builtinFunc{"clearTimeout", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return nil, ArErr{"TypeError", "Expected 1 argument, got " + fmt.Sprint(len(args)), 0, "", "", true} + } + if typeof(args[0]) != "number" { + return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[0]), 0, "", "", true} + } + if !args[0].(number).IsInt() { + return nil, ArErr{"TypeError", "Expected integer, got float", 0, "", "", true} + } + n := args[0].(number).Num().Int64() + for i, v := range TimeoutList { + if v == int(n) { + TimeoutList = append(TimeoutList[:i], TimeoutList[i+1:]...) + break + } + } + js.Global().Call("clearTimeout", n) + return nil, ArErr{} + }}, + "clearInterval": builtinFunc{"clearInterval", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return nil, ArErr{"TypeError", "Expected 1 argument, got " + fmt.Sprint(len(args)), 0, "", "", true} + } + if typeof(args[0]) != "number" { + return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[0]), 0, "", "", true} + } + if !args[0].(number).IsInt() { + return nil, ArErr{"TypeError", "Expected integer, got float", 0, "", "", true} + } + n := args[0].(number).Num().Int64() + for i, v := range IntervalList { + if v == int(n) { + IntervalList = append(IntervalList[:i], IntervalList[i+1:]...) + break + } + } + js.Global().Call("clearInterval", n) + return nil, ArErr{} + }}, +}) diff --git a/wasm/argon_wasm.js b/wasm/argon_wasm.js index 187509b..bc4935e 100644 --- a/wasm/argon_wasm.js +++ b/wasm/argon_wasm.js @@ -342,7 +342,7 @@ window.ArgonWASMRuntime = async (config = {}) => { // func resetMemoryDataView() "runtime.resetMemoryDataView": (sp) => { sp >>>= 0; - this.mem = memory; + this.mem = new DataView(this._inst.exports.mem.buffer); }, // func nanotime1() int64 "runtime.nanotime1": (sp) => { diff --git a/wasm/index.html b/wasm/index.html index 06beca2..c14ce07 100644 --- a/wasm/index.html +++ b/wasm/index.html @@ -67,7 +67,7 @@

Argon WASM Runtime Example

-