mirror of
https://github.com/Open-Argon/argon-v3.git
synced 2025-12-06 08:56:07 +00:00
make wasm not require reinit
This commit is contained in:
@@ -2,9 +2,12 @@ package main
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
func makeGlobal() ArObject {
|
func makeGlobal(allowDocument bool) ArObject {
|
||||||
var vars = Map(anymap{})
|
var vars = Map(anymap{})
|
||||||
vars.obj["global"] = vars
|
vars.obj["global"] = vars
|
||||||
|
if allowDocument {
|
||||||
|
vars.obj["document"] = ArDocument
|
||||||
|
}
|
||||||
vars.obj["term"] = ArTerm
|
vars.obj["term"] = ArTerm
|
||||||
vars.obj["number"] = builtinFunc{"number", ArgonNumber}
|
vars.obj["number"] = builtinFunc{"number", ArgonNumber}
|
||||||
vars.obj["string"] = builtinFunc{"string", ArgonString}
|
vars.obj["string"] = builtinFunc{"string", ArgonString}
|
||||||
|
|||||||
210
src/document.go
Normal file
210
src/document.go
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
func windowElement(element js.Value) ArObject {
|
||||||
|
return ArObject{
|
||||||
|
TYPE: "map",
|
||||||
|
obj: anymap{
|
||||||
|
"innerHTML": builtinFunc{"innerHTML", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "innerHTML only accepts strings", 0, "", "", true}
|
||||||
|
}
|
||||||
|
element.Set("innerHTML", args[0].(string))
|
||||||
|
}
|
||||||
|
return element.Get("innerHTML").String(), ArErr{}
|
||||||
|
}},
|
||||||
|
"innerText": builtinFunc{"innerText", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "innerText only accepts strings", 0, "", "", true}
|
||||||
|
}
|
||||||
|
element.Set("innerText", args[0].(string))
|
||||||
|
}
|
||||||
|
return element.Get("innerText").String(), ArErr{}
|
||||||
|
}},
|
||||||
|
"addEventListener": builtinFunc{"addEventListener", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for addEventListener", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "addEventListener's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
event := args[0].(string)
|
||||||
|
if typeof(args[1]) != "function" {
|
||||||
|
return nil, ArErr{"Argument Error", "addEventListener's second argument must be a function", 0, "", "", true}
|
||||||
|
}
|
||||||
|
callable := args[1]
|
||||||
|
element.Call("addEventListener", event, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
runCall(call{
|
||||||
|
callable: callable,
|
||||||
|
args: []any{},
|
||||||
|
}, stack{}, 0)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"removeEventListener": builtinFunc{"removeEventListener", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for removeEventListener", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeEventListener's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
event := args[0].(string)
|
||||||
|
if typeof(args[1]) != "function" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeEventListener's second argument must be a function", 0, "", "", true}
|
||||||
|
}
|
||||||
|
callable := args[1]
|
||||||
|
element.Call("removeEventListener", event, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
runCall(call{
|
||||||
|
callable: callable,
|
||||||
|
args: []any{},
|
||||||
|
}, stack{}, 0)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"appendChild": builtinFunc{"appendChild", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for appendChild", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "map" {
|
||||||
|
return nil, ArErr{"Argument Error", "appendChild's first argument must be a map", 0, "", "", true}
|
||||||
|
}
|
||||||
|
child := args[0].(anymap)
|
||||||
|
if child["__TYPE__"] != "windowElement" {
|
||||||
|
return nil, ArErr{"Argument Error", "appendChild's first argument must be an element", 0, "", "", true}
|
||||||
|
}
|
||||||
|
element.Call("appendChild", child["__element__"])
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"removeChild": builtinFunc{"removeChild", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for removeChild", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "map" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeChild's first argument must be a map", 0, "", "", true}
|
||||||
|
}
|
||||||
|
child := args[0].(anymap)
|
||||||
|
if child["__TYPE__"] != "windowElement" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeChild's first argument must be an element", 0, "", "", true}
|
||||||
|
}
|
||||||
|
element.Call("removeChild", child["__element__"])
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"setAttribute": builtinFunc{"setAttribute", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for setAttribute", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "setAttribute's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
element.Call("setAttribute", args[0].(string), anyToArgon(args[1], false, false, 3, 0, false, 0))
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"__element__": element,
|
||||||
|
"__TYPE__": "windowElement",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ArDocument = Map(
|
||||||
|
anymap{
|
||||||
|
"body": windowElement(js.Global().Get("document").Get("body")),
|
||||||
|
"head": windowElement(js.Global().Get("document").Get("head")),
|
||||||
|
"getElementById": builtinFunc{"getElementById", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for getElementById", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "getElementById's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
id := args[0].(string)
|
||||||
|
result := js.Global().Get("document").Call("getElementById", id)
|
||||||
|
if js.Null().Equal(result) {
|
||||||
|
return nil, ArErr{}
|
||||||
|
}
|
||||||
|
return windowElement(result), ArErr{}
|
||||||
|
}},
|
||||||
|
"createElement": builtinFunc{"createElement", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for createElement", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "createElement's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
tag := args[0].(string)
|
||||||
|
return windowElement(js.Global().Get("document").Call("createElement", tag)), ArErr{}
|
||||||
|
}},
|
||||||
|
"createTextNode": builtinFunc{"createTextNode", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for createTextNode", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "createTextNode's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
text := args[0].(string)
|
||||||
|
return windowElement(js.Global().Get("document").Call("createTextNode", text)), ArErr{}
|
||||||
|
}},
|
||||||
|
"createComment": builtinFunc{"createComment", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for createComment", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "createComment's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
text := args[0].(string)
|
||||||
|
return windowElement(js.Global().Get("document").Call("createComment", text)), ArErr{}
|
||||||
|
}},
|
||||||
|
"createDocumentFragment": builtinFunc{"createDocumentFragment", func(args ...any) (any, ArErr) {
|
||||||
|
return windowElement(js.Global().Get("document").Call("createDocumentFragment")), ArErr{}
|
||||||
|
}},
|
||||||
|
"addEventListener": builtinFunc{"addEventListener", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for addEventListener", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "addEventListener's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
event := args[0].(string)
|
||||||
|
if typeof(args[1]) != "function" {
|
||||||
|
return nil, ArErr{"Argument Error", "addEventListener's second argument must be a function", 0, "", "", true}
|
||||||
|
}
|
||||||
|
callable := args[1]
|
||||||
|
js.Global().Get("document").Call("addEventListener", event, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
runCall(call{
|
||||||
|
callable: callable,
|
||||||
|
args: []any{},
|
||||||
|
}, stack{}, 0)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"removeEventListener": builtinFunc{"removeEventListener", func(args ...any) (any, ArErr) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, ArErr{"Argument Error", "Not enough arguments for removeEventListener", 0, "", "", true}
|
||||||
|
}
|
||||||
|
if typeof(args[0]) != "string" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeEventListener's first argument must be a string", 0, "", "", true}
|
||||||
|
}
|
||||||
|
event := args[0].(string)
|
||||||
|
if typeof(args[1]) != "function" {
|
||||||
|
return nil, ArErr{"Argument Error", "removeEventListener's second argument must be a function", 0, "", "", true}
|
||||||
|
}
|
||||||
|
callable := args[1]
|
||||||
|
js.Global().Get("document").Call("removeEventListener", event, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
runCall(call{
|
||||||
|
callable: callable,
|
||||||
|
args: []any{},
|
||||||
|
}, stack{}, 0)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
return nil, ArErr{}
|
||||||
|
}},
|
||||||
|
"__TYPE__": "document",
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -23,10 +23,14 @@ func main() {
|
|||||||
obj := js.Global().Get("Object").New()
|
obj := js.Global().Get("Object").New()
|
||||||
obj.Set("eval", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
obj.Set("eval", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
code := ""
|
code := ""
|
||||||
if len(args) > 0 {
|
allowDocument := false
|
||||||
|
if len(args) >= 1 {
|
||||||
code = args[0].String()
|
code = args[0].String()
|
||||||
}
|
}
|
||||||
val, err := wasmRun(code)
|
if len(args) >= 2 {
|
||||||
|
allowDocument = args[1].Bool()
|
||||||
|
}
|
||||||
|
val, err := wasmRun(code, allowDocument)
|
||||||
if err.EXISTS {
|
if err.EXISTS {
|
||||||
panicErr(err)
|
panicErr(err)
|
||||||
return js.Null()
|
return js.Null()
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ func argonToJsValid(argon any) any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func wasmRun(code string) (any, ArErr) {
|
func wasmRun(code string, allowDocument bool) (any, ArErr) {
|
||||||
|
initRandom()
|
||||||
|
global := makeGlobal(allowDocument)
|
||||||
lines := strings.Split(code, "\n")
|
lines := strings.Split(code, "\n")
|
||||||
codelines := []UNPARSEcode{}
|
codelines := []UNPARSEcode{}
|
||||||
for i := 0; i < len(lines); i++ {
|
for i := 0; i < len(lines); i++ {
|
||||||
@@ -49,7 +51,7 @@ func wasmRun(code string) (any, ArErr) {
|
|||||||
if translationerr.EXISTS {
|
if translationerr.EXISTS {
|
||||||
return nil, translationerr
|
return nil, translationerr
|
||||||
}
|
}
|
||||||
global := newscope()
|
local := newscope()
|
||||||
localvars := Map(anymap{
|
localvars := Map(anymap{
|
||||||
"program": Map(anymap{
|
"program": Map(anymap{
|
||||||
"args": []any{},
|
"args": []any{},
|
||||||
@@ -67,5 +69,5 @@ func wasmRun(code string) (any, ArErr) {
|
|||||||
"scope": global,
|
"scope": global,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
return ThrowOnNonLoop(run(translated, stack{vars, localvars, global}))
|
return ThrowOnNonLoop(run(translated, stack{global, localvars, local}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
window.ArgonWASMRuntime = async (config = {}) => {
|
window.ArgonWASMRuntime = async (config = {}) => {
|
||||||
const term = config.console || console;
|
const term = config.console || console;
|
||||||
|
const path = config.path || "/bin/argon.wasm";
|
||||||
if (typeof global !== "undefined") {
|
if (typeof global !== "undefined") {
|
||||||
} else if (typeof window !== "undefined") {
|
} else if (typeof window !== "undefined") {
|
||||||
window.global = window;
|
window.global = window;
|
||||||
@@ -309,6 +310,7 @@ window.ArgonWASMRuntime = async (config = {}) => {
|
|||||||
};
|
};
|
||||||
const timeOrigin = Date.now() - performance.now();
|
const timeOrigin = Date.now() - performance.now();
|
||||||
this.importObject = {
|
this.importObject = {
|
||||||
|
env: {},
|
||||||
go: {
|
go: {
|
||||||
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||||
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||||
@@ -340,7 +342,7 @@ window.ArgonWASMRuntime = async (config = {}) => {
|
|||||||
// func resetMemoryDataView()
|
// func resetMemoryDataView()
|
||||||
"runtime.resetMemoryDataView": (sp) => {
|
"runtime.resetMemoryDataView": (sp) => {
|
||||||
sp >>>= 0;
|
sp >>>= 0;
|
||||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
this.mem = memory;
|
||||||
},
|
},
|
||||||
// func nanotime1() int64
|
// func nanotime1() int64
|
||||||
"runtime.nanotime1": (sp) => {
|
"runtime.nanotime1": (sp) => {
|
||||||
@@ -646,11 +648,7 @@ window.ArgonWASMRuntime = async (config = {}) => {
|
|||||||
}
|
}
|
||||||
_resume() {
|
_resume() {
|
||||||
if (this.exited) {
|
if (this.exited) {
|
||||||
(async () => {
|
throw new Error("Go program has already exited");
|
||||||
await run();
|
|
||||||
this._inst.exports.resume();
|
|
||||||
})();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this._inst.exports.resume();
|
this._inst.exports.resume();
|
||||||
if (this.exited) {
|
if (this.exited) {
|
||||||
@@ -668,13 +666,11 @@ window.ArgonWASMRuntime = async (config = {}) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const go = new Go();
|
const go = new Go();
|
||||||
const file = await fetch("bin/argon.wasm");
|
const file = fetch(path);
|
||||||
const run = async () => {
|
|
||||||
const result = await WebAssembly.instantiateStreaming(
|
const result = await WebAssembly.instantiateStreaming(
|
||||||
file.clone(),
|
(await file).clone(),
|
||||||
go.importObject
|
go.importObject
|
||||||
);
|
);
|
||||||
|
|
||||||
go.run(result.instance);
|
go.run(result.instance);
|
||||||
};
|
};
|
||||||
await run();
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Argon WASM Runtime Example</title>
|
<title>Argon WASM Runtime Example</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<style>
|
<style>
|
||||||
.terminal {
|
.terminal {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||||
min-height: 250px;
|
min-height: 250px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
.terminal * {
|
.terminal * {
|
||||||
min-height: 1rem;
|
min-height: 1rem;
|
||||||
@@ -60,27 +62,28 @@
|
|||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="argon_wasm.js"></script>
|
<script src="/argon_wasm.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Argon WASM Runtime Example</h1>
|
<h1>Argon WASM Runtime Example</h1>
|
||||||
<button id="run" class="runButton">run</button>
|
<button id="run" class="runButton">run</button>
|
||||||
<textarea id="editbox" class="editbox">
|
<textarea id="editbox" class="editbox" spellcheck="flase" autocapitalize="false">
|
||||||
term.log("hello world")</textarea
|
term.log("hello world")</textarea
|
||||||
>
|
>
|
||||||
<pre id="terminal" class="terminal">
|
<pre
|
||||||
|
id="terminal"
|
||||||
</pre>
|
class="terminal"
|
||||||
|
><div> ____ </div><div> /\ |___ \ </div><div> / \ _ __ __ _ ___ _ __ __ ____) |</div><div> / /\ \ | '__/ _` |/ _ \| '_ \ \ \ / /__ < </div><div> / ____ \| | | (_| | (_) | | | | \ V /___) |</div><div> /_/ \_\_| \__, |\___/|_| |_| \_/|____/ </div><div> __/ | </div><div> |___/ </div><div>----------------------------------------------</div><div>Welcome to ARGON for WASM!</div><div>write code above and click run to see it work like magic!</div></pre>
|
||||||
<script>
|
<script>
|
||||||
const output = document.getElementById("terminal");
|
const output = document.getElementById("terminal");
|
||||||
const editbox = document.getElementById("editbox");
|
const editbox = document.getElementById("editbox");
|
||||||
const run = document.getElementById("run");
|
const run = document.getElementById("run");
|
||||||
run.addEventListener("click", () => {
|
run.addEventListener("click", async () => {
|
||||||
output.innerHTML = "";
|
output.innerHTML = "";
|
||||||
setTimeout(()=>Ar.eval(editbox.value), 100)
|
setTimeout(() => Ar.eval(editbox.value, true), 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
ArgonWASMRuntime({
|
const runAr = ArgonWASMRuntime({
|
||||||
console: {
|
console: {
|
||||||
log: (...msg) => {
|
log: (...msg) => {
|
||||||
const p = document.createElement("div");
|
const p = document.createElement("div");
|
||||||
|
|||||||
Reference in New Issue
Block a user