34 Commits

Author SHA1 Message Date
2543822418 Revert "fix incorrect function name"
This reverts commit 5ceff0ddd2.
2023-06-13 23:06:05 +01:00
afbf868703 Revert "make maps oop"
This reverts commit 199b2320dd.
2023-06-13 23:03:46 +01:00
William Bell
1c048579a5 Merge branch 'master' into master 2023-06-13 22:56:48 +01:00
199b2320dd make maps oop 2023-06-13 22:54:48 +01:00
857eb442c2 update to support new oop 2023-06-13 22:42:44 +01:00
William Bell
5ceff0ddd2 fix incorrect function name 2023-06-13 22:42:44 +01:00
2d3c7c42ce make maps oop 2023-06-13 22:42:44 +01:00
90b506d22f update config 2023-03-28 23:30:24 +01:00
f9777611dd Merge remote-tracking branch 'upstream/master' 2023-03-28 23:18:46 +01:00
bc3e50697f Merge remote-tracking branch 'upstream/master' 2023-03-28 17:10:18 +01:00
6226cc52ac undo arvalid bug 2023-03-28 17:04:14 +01:00
c881d06cb5 fix arvalid bug 2023-03-28 17:03:39 +01:00
584841030c Merge remote-tracking branch 'upstream/master' 2023-03-28 17:01:54 +01:00
58c57f154b add try catch 2023-03-28 16:40:04 +01:00
c698b878da Merge remote-tracking branch 'upstream/master' 2023-03-28 16:34:39 +01:00
280635d46e update 2023-03-28 00:23:57 +01:00
e05267c886 fix built in functions 2023-03-28 00:23:57 +01:00
4c412a763a move spec to docs 2023-03-26 22:09:34 +01:00
de95c3e8b5 add sort to strings 2023-03-26 22:04:57 +01:00
d0d73db6cf make not relelative 2023-03-26 21:44:05 +01:00
aea3b73e71 abs and modify operations so they are opp 2023-03-26 21:44:05 +01:00
William Bell
e06d28ca02 Update readme.md 2023-03-26 00:08:44 +00:00
bf145db749 add interval and timeout 2023-03-25 23:35:13 +00:00
0514783230 add other trig funcs 2023-03-25 23:35:12 +00:00
7ef9384d76 edit readme 2023-03-25 21:01:33 +00:00
957029ebd4 Merge remote-tracking branch 'upstream/master' 2023-03-25 20:42:09 +00:00
afc5ae2086 dont require clone 2023-03-25 19:52:07 +00:00
a6c14b49a5 make wasm not require reinit 2023-03-25 19:50:26 +00:00
1e625a589a Merge remote-tracking branch 'upstream/master' 2023-03-25 19:49:58 +00:00
5e65ff01ac Merge remote-tracking branch 'upstream/master' 2023-03-25 19:37:15 +00:00
5e48a70c77 make wasm work 2023-03-25 18:52:33 +00:00
William Bell
69faa23ea9 Merge branch 'Open-Argon:master' into master 2023-03-25 01:20:44 +00:00
William Bell
126d287611 Merge branch 'Open-Argon:master' into master 2023-03-25 00:45:26 +00:00
97ec428aca make wasm work 2023-03-25 00:45:13 +00:00
19 changed files with 612 additions and 135 deletions

2
build
View File

@@ -1 +1 @@
go build -o bin/argon ./src GOOS=js GOARCH=wasm go build -o wasm/bin/argon.wasm ./src

View File

@@ -1,2 +1,4 @@
@echo off @echo off
go build -o bin/argon.exe ./src set GOOS=js
set GOARCH=wasm
go build -o wasm/bin/argon.wasm ./src

2
merge Executable file
View File

@@ -0,0 +1,2 @@
git fetch upstream
git merge upstream/master master

2
merge.bat Normal file
View File

@@ -0,0 +1,2 @@
git fetch upstream
git merge upstream/master master

View File

@@ -2,12 +2,24 @@
<p> <p>
<img width="150" src="logos/ArLogo.png"> <img width="150" src="logos/ArLogo.png">
</p> </p>
<h1>Argon v3</h1> <h1>Argon v3.wasm</h1>
</div> </div>
### HEADS UP! 🙂
Argon v3.wasm is a fork of Argon v3 which has had parts rewritten for support in WebAssembly (WASM).
It includes all the same features and functionality as Argon v3, but has been compiled to run efficiently on WebAssembly.
Please note that Argon v3.wasm can only be compiled for use with WebAssembly.
---
ARGON 3 is a math-driven programming language designed to make code easy to read and write. It's not meant to be fast, as it's interpreted. This specification should be used as a guideline, and is subject to change for later versions. Later updates for Argon 3 should be backwards compatible (where possible) with code designed for older versions of the interpreter. ARGON 3 is a math-driven programming language designed to make code easy to read and write. It's not meant to be fast, as it's interpreted. This specification should be used as a guideline, and is subject to change for later versions. Later updates for Argon 3 should be backwards compatible (where possible) with code designed for older versions of the interpreter.
## 📚 Features ## 📚 Features
- Easy to read and write: Argon 3 is designed with clarity of code in mind, making it easier for you and others to read and write code. - Easy to read and write: Argon 3 is designed with clarity of code in mind, making it easier for you and others to read and write code.
- All numbers are stored as rational numbers, preventing precision errors. - All numbers are stored as rational numbers, preventing precision errors.
- Math-driven: Designed for mathematical computations, Argon 3 uses techniques and rules set in maths. It's designed to be easy for mathematicians to write and understand algorithms in. - Math-driven: Designed for mathematical computations, Argon 3 uses techniques and rules set in maths. It's designed to be easy for mathematicians to write and understand algorithms in.
@@ -16,9 +28,11 @@ ARGON 3 is a math-driven programming language designed to make code easy to read
- Lightweight: The Argon 3 interpreter is small and doesn't require a lot of system resources to run. - Lightweight: The Argon 3 interpreter is small and doesn't require a lot of system resources to run.
## 💻 Installation ## 💻 Installation
As of now, Argon 3 does not have an installer. Feel free to clone this repo and run the `build` file for your plateform. the build will be found in `bin/argon(.exe)`. As of now, Argon 3 does not have an installer. Feel free to clone this repo and run the `build` file for your plateform. the build will be found in `bin/argon(.exe)`.
## 📖 Usage ## 📖 Usage
To use Argon 3, you can create a file with the .ar extension and write your code in it. Then, you can run your code using the interpreter. For example, if you have a file called example.ar, you can run it using the following command: To use Argon 3, you can create a file with the .ar extension and write your code in it. Then, you can run your code using the interpreter. For example, if you have a file called example.ar, you can run it using the following command:
``` ```
@@ -38,7 +52,7 @@ f(x) = x^2 + 2*x + 1
term.log('f(10) =', f(10)) term.log('f(10) =', f(10))
``` ```
This code defines a function f(x) that calculates x^2 + 2*x + 1. It then calls the function with an argument of 10 and logs the result to the console. This code defines a function f(x) that calculates x^2 + 2\*x + 1. It then calls the function with an argument of 10 and logs the result to the console.
Please note that this example is subject to change as the specification is in beta and may be updated frequently. Please note that this example is subject to change as the specification is in beta and may be updated frequently.

2
run
View File

@@ -1,2 +0,0 @@
# run the go run command passing the path to the main.go file, with the working directory set to the bin folder. pass in the arguments
go run ./src "$@"

View File

@@ -1,5 +0,0 @@
@echo off
:: run the go run command passing the path to the main.go file, with the working directory set to the bin folder. pass in the arguments
go run ./src %*

3
serve.bat Normal file
View File

@@ -0,0 +1,3 @@
@echo off
cd ./wasm
npx serve

View File

@@ -533,7 +533,7 @@ func ArArray(arr []any) ArObject {
}, },
} }
val.obj["__Equal__"] = builtinFunc{ val.obj["__Equal__"] = builtinFunc{
"__Equal__", "__LessThanEqual__",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
if len(args) != 1 { if len(args) != 1 {
return nil, ArErr{ return nil, ArErr{

View File

@@ -5,10 +5,14 @@ import (
"os" "os"
) )
func makeGlobal() ArObject { func makeGlobal(allowDocument bool) ArObject {
var vars = anymap{} var vars = anymap{}
vars["global"] = vars vars["global"] = vars
vars["term"] = ArTerm vars["term"] = ArTerm
if allowDocument {
vars["document"] = ArDocument
}
vars["js"] = ArJS
vars["number"] = builtinFunc{"number", ArgonNumber} vars["number"] = builtinFunc{"number", ArgonNumber}
vars["string"] = builtinFunc{"string", ArgonString} vars["string"] = builtinFunc{"string", ArgonString}
vars["infinity"] = infinity vars["infinity"] = infinity

View File

@@ -4,6 +4,6 @@ var websiteLang = "https://argon.wbell.dev/"
var docs = "https://argon.wbell.dev/docs/" var docs = "https://argon.wbell.dev/docs/"
var mainrepo = "https://github.com/Open-Argon/argon-v3" var mainrepo = "https://github.com/Open-Argon/argon-v3"
var mainissuesPage = "https://github.com/Open-Argon/argon-v3/issues" var mainissuesPage = "https://github.com/Open-Argon/argon-v3/issues"
var fork = false var fork = true
var forkrepo = "" var forkrepo = "https://github.com/Open-Argon/argon-v3.wasm"
var forkissuesPage = "" var forkissuesPage = "https://github.com/Open-Argon/argon-v3.wasm/issues"

213
src/document.go Normal file
View File

@@ -0,0 +1,213 @@
package main
import (
"syscall/js"
)
func windowElement(element js.Value) ArObject {
return ArObject{
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": builtinFunc{"getElementById", func(args ...any) (any, ArErr) {
return windowElement(js.Global().Get("document").Get("body")), ArErr{}
}},
"head": builtinFunc{"getElementById", func(args ...any) (any, ArErr) {
return windowElement(js.Global().Get("document").Get("head")), ArErr{}
}},
"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",
},
)

View File

@@ -2,6 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"github.com/jwalton/go-supportscolor"
) )
type ArErr struct { type ArErr struct {
@@ -19,5 +21,9 @@ func panicErr(err ArErr) {
fmt.Println(" " + err.code) fmt.Println(" " + err.code)
fmt.Println() fmt.Println()
} }
if supportscolor.Stdout().SupportsColor {
fmt.Printf("\x1b[%dm%s\x1b[0m", 91, fmt.Sprint(err.TYPE, ": ", err.message, "\n")) fmt.Printf("\x1b[%dm%s\x1b[0m", 91, fmt.Sprint(err.TYPE, ": ", err.message, "\n"))
} else {
fmt.Println(fmt.Sprint(err.TYPE, ": ", err.message))
}
} }

View File

@@ -5,7 +5,6 @@ import (
"errors" "errors"
"log" "log"
"os" "os"
"path/filepath"
) )
var imported = make(map[string]ArObject) var imported = make(map[string]ArObject)
@@ -48,6 +47,12 @@ func readFile(path string) []UNPARSEcode {
} }
func importMod(realpath string, origin string, main bool, global ArObject) (ArObject, ArErr) { func importMod(realpath string, origin string, main bool, global ArObject) (ArObject, ArErr) {
return ArObject{}, ArErr{
TYPE: "Import Error",
message: "importing in WASM is currently not supported",
EXISTS: true,
}
/*
extention := filepath.Ext(realpath) extention := filepath.Ext(realpath)
path := realpath path := realpath
if extention == "" { if extention == "" {
@@ -114,7 +119,7 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
for _, arg := range withoutarfile { for _, arg := range withoutarfile {
ArgsArArray = append(ArgsArArray, arg) ArgsArArray = append(ArgsArArray, arg)
} }
local := newscope() global := newscope()
localvars := Map(anymap{ localvars := Map(anymap{
"program": Map(anymap{ "program": Map(anymap{
"args": ArArray(ArgsArArray), "args": ArArray(ArgsArArray),
@@ -126,7 +131,7 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
if _, ok := args[0].(string); !ok { if _, ok := args[0].(string); !ok {
return nil, ArErr{"Import Error", "Invalid argument type", 0, realpath, "", true} return nil, ArErr{"Import Error", "Invalid argument type", 0, realpath, "", true}
} }
return importMod(args[0].(string), filepath.Dir(p), false, global) return importMod(args[0].(string), filepath.Dir(p), false)
}}, }},
"cwd": ex, "cwd": ex,
"exc": exc, "exc": exc,
@@ -138,11 +143,12 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
"scope": global, "scope": global,
}), }),
}) })
_, runimeErr := ThrowOnNonLoop(run(translated, stack{global, localvars, local})) _, runimeErr := ThrowOnNonLoop(run(translated, stack{vars, localvars, global}))
importing[p] = false importing[p] = false
if runimeErr.EXISTS { if runimeErr.EXISTS {
return ArObject{}, runimeErr return ArObject{}, runimeErr
} }
imported[p] = local imported[p] = global
return local, ArErr{} return global, ArErr{}
*/
} }

View File

@@ -1,9 +1,9 @@
package main package main
import ( import (
"bufio"
"fmt" "fmt"
"os" "os"
"syscall/js"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -12,12 +12,15 @@ func input(args ...any) string {
output := []any{} output := []any{}
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
output = append(output, anyToArgon(args[i], false, true, 3, 0, true, 0)) output = append(output, anyToArgon(args[i], false, true, 3, 0, true, 0))
if i != len(args)-1 {
output = append(output, " ")
} }
fmt.Print(output...) }
scanner := bufio.NewScanner(os.Stdin) text := fmt.Sprint(output...)
scanner.Scan() fmt.Print(text)
input := scanner.Text() inputData := js.Global().Get("getInput").Invoke(fmt.Sprint(output...)).String()
return input fmt.Println(inputData)
return (inputData)
} }
func getPassword(args ...any) (string, error) { func getPassword(args ...any) (string, error) {

View File

@@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"syscall/js"
) )
// args without the program path // args without the program path
@@ -15,6 +16,7 @@ func newscope() ArObject {
} }
func main() { func main() {
c := make(chan ArObject)
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
fmt.Println("There was a fundamental error in argon v3 that caused it to crash.") fmt.Println("There was a fundamental error in argon v3 that caused it to crash.")
@@ -37,18 +39,24 @@ func main() {
}() }()
initRandom() initRandom()
garbageCollect() garbageCollect()
global := makeGlobal() obj := js.Global().Get("Object").New()
if len(Args) == 0 { obj.Set("eval", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
shell(global) code := ""
os.Exit(0) allowDocument := false
if len(args) >= 1 {
code = args[0].String()
} }
ex, e := os.Getwd() if len(args) >= 2 {
if e != nil { allowDocument = args[1].Bool()
panic(e)
} }
_, err := importMod(Args[0], ex, true, global) val, err := wasmRun(code, allowDocument)
if err.EXISTS { if err.EXISTS {
panicErr(err) panicErr(err)
os.Exit(1) return js.Null()
} }
return js.ValueOf(argonToJsValid(val))
}))
js.Global().Set("Ar", obj)
<-c
} }

View File

@@ -44,6 +44,7 @@ func parseGenericImport(code UNPARSEcode, index int, codeline []UNPARSEcode) (Ar
} }
func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) { func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
return nil, ArErr{"Import Error", "importing in WASM is currently not supported", importOBJ.line, importOBJ.path, importOBJ.code, true}
val, err := runVal(importOBJ.filePath, stack, stacklevel+1) val, err := runVal(importOBJ.filePath, stack, stacklevel+1)
val = ArValidToAny(val) val = ArValidToAny(val)
if err.EXISTS { if err.EXISTS {

View File

@@ -46,7 +46,6 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i
return parseTryCatch(code, index, codelines) return parseTryCatch(code, index, codelines)
} }
} }
if isLine >= 1 { if isLine >= 1 {
if isDoWrap(code) { if isDoWrap(code) {
return parseDoWrap(code, index, codelines) return parseDoWrap(code, index, codelines)

221
src/wasm.go Normal file
View File

@@ -0,0 +1,221 @@
package main
import (
"fmt"
"strings"
"syscall/js"
)
func argonToJsValid(argon any) any {
switch x := argon.(type) {
case number:
f, _ := x.Float64()
return f
case ArObject:
if typeof(x) == "array" {
arr := js.Global().Get("Array").New()
for i, v := range x.obj["__value__"].([]any) {
arr.SetIndex(i, argonToJsValid(v))
}
return arr
} else if typeof(x) == "string" {
return x.obj["__value__"].(string)
}
obj := js.Global().Get("Object").New()
for k, v := range x.obj {
obj.Set(anyToArgon(k, false, false, 3, 0, false, 0), argonToJsValid(v))
}
return obj
case bool, string:
return x
default:
return nil
}
}
func wasmRun(code string, allowDocument bool) (any, ArErr) {
JSclearTimers()
initRandom()
global := makeGlobal(allowDocument)
lines := strings.Split(code, "\n")
codelines := []UNPARSEcode{}
for i := 0; i < len(lines); i++ {
codelines = append(codelines, UNPARSEcode{
lines[i],
lines[i],
i + 1,
"<wasm>",
})
}
translated, translationerr := translate(codelines)
if translationerr.EXISTS {
return nil, translationerr
}
local := newscope()
localvars := Map(anymap{
"program": Map(anymap{
"args": []any{},
"origin": "",
"import": builtinFunc{"import", func(args ...any) (any, ArErr) {
return nil, ArErr{"Import Error", "Cannot Import in WASM", 0, "<wasm>", "", true}
}},
"cwd": "",
"exc": "",
"file": Map(anymap{
"name": "<wasm>",
"path": "",
}),
"main": true,
"scope": global,
}),
})
return ThrowOnNonLoop(run(translated, stack{global, localvars, local}))
}
func await(awaitable js.Value) ([]js.Value, []js.Value) {
then := make(chan []js.Value)
defer close(then)
thenFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
then <- args
return nil
})
defer thenFunc.Release()
catch := make(chan []js.Value)
defer close(catch)
catchFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
catch <- args
return nil
})
defer catchFunc.Release()
awaitable.Call("then", thenFunc).Call("catch", catchFunc)
select {
case result := <-then:
return result, nil
case err := <-catch:
return nil, err
}
}
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, "<wasm>", "", true}
}
if typeof(args[0]) != "function" {
return nil, ArErr{"TypeError", "Expected function, got " + typeof(args[0]), 0, "<wasm>", "", 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, "<wasm>", "", true}
}
if !args[1].(number).IsInt() {
return nil, ArErr{"TypeError", "Expected integer, got float", 0, "<wasm>", "", 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, "<wasm>", "", true}
}
if typeof(args[0]) != "function" {
return nil, ArErr{"TypeError", "Expected function, got " + typeof(args[0]), 0, "<wasm>", "", 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, "<wasm>", "", true}
}
if !args[1].(number).IsInt() {
return nil, ArErr{"TypeError", "Expected integer, got float", 0, "<wasm>", "", 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, "<wasm>", "", true}
}
if typeof(args[0]) != "number" {
return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[0]), 0, "<wasm>", "", true}
}
if !args[0].(number).IsInt() {
return nil, ArErr{"TypeError", "Expected integer, got float", 0, "<wasm>", "", 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, "<wasm>", "", true}
}
if typeof(args[0]) != "number" {
return nil, ArErr{"TypeError", "Expected number, got " + typeof(args[0]), 0, "<wasm>", "", true}
}
if !args[0].(number).IsInt() {
return nil, ArErr{"TypeError", "Expected integer, got float", 0, "<wasm>", "", 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{}
}},
})