From 4f3d419c2855394b015b63529f86c8a291ed53fd Mon Sep 17 00:00:00 2001 From: William Bell Date: Tue, 21 Mar 2023 23:03:25 +0000 Subject: [PATCH] add subprocess --- .gitignore | 1 - go.mod | 8 +-- src/array.go | 2 +- src/boolean.go | 1 - src/built-in-functions.go | 10 --- src/built-ins.go | 3 +- src/getIndex.go | 91 ------------------------- src/input.go | 4 +- src/string.go | 7 +- src/subprocess.go | 139 ++++++++++++++++++++++++++++++++++++++ src/term-class.go | 76 +++++++++++++-------- src/typeof.go | 6 +- 12 files changed, 202 insertions(+), 146 deletions(-) create mode 100644 src/subprocess.go diff --git a/.gitignore b/.gitignore index 9e87c05..c5e82d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -node_modules bin \ No newline at end of file diff --git a/go.mod b/go.mod index 38f4516..a1d4992 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,10 @@ require ( ) require ( - github.com/jwalton/go-supportscolor v1.1.0 // indirect + github.com/jwalton/go-supportscolor v1.1.0 github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/term v0.6.0 + golang.org/x/text v0.8.0 ) diff --git a/src/array.go b/src/array.go index b65d374..49f693b 100644 --- a/src/array.go +++ b/src/array.go @@ -68,7 +68,7 @@ func ArArray(arr []any) ArObject { // a[0] is start // a[1] is end // a[2] is step - if len(a) < 0 || len(a) > 3 { + if len(a) > 3 { return nil, ArErr{"TypeError", "expected 1 to 3 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true} } var ( diff --git a/src/boolean.go b/src/boolean.go index 240bf1b..1e20239 100644 --- a/src/boolean.go +++ b/src/boolean.go @@ -24,7 +24,6 @@ func anyToBool(x any) bool { default: return true } - } var booleanCompile = makeRegex(`( )*(true|false|null)( )*`) diff --git a/src/built-in-functions.go b/src/built-in-functions.go index d3b19ed..11b3a22 100644 --- a/src/built-in-functions.go +++ b/src/built-in-functions.go @@ -12,16 +12,6 @@ type builtinFunc struct { func ArgonString(args ...any) (any, ArErr) { return ArString(anyToArgon(args[0], true, false, 3, 0, false, 0)), ArErr{} } -func ArgonPassworInput(args ...any) (any, ArErr) { - resp, err := getPassword(args...) - if err != nil { - return nil, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} - } - return ArString(resp), ArErr{} -} -func ArgonInput(args ...any) (any, ArErr) { - return input(args...), ArErr{} -} func ArgonNumber(args ...any) (any, ArErr) { if len(args) == 0 { diff --git a/src/built-ins.go b/src/built-ins.go index f91ef90..ca84e70 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -7,8 +7,6 @@ var vars = Map(anymap{}) func init() { vars.obj["global"] = vars vars.obj["term"] = ArTerm - vars.obj["input"] = builtinFunc{"input", ArgonInput} - vars.obj["passwordInput"] = builtinFunc{"passwordInput", ArgonPassworInput} vars.obj["number"] = builtinFunc{"number", ArgonNumber} vars.obj["string"] = builtinFunc{"string", ArgonString} vars.obj["infinity"] = infinity @@ -151,4 +149,5 @@ func init() { } return ArArray([]any{}), ArErr{} }} + vars.obj["subprocess"] = builtinFunc{"subprocess", ArSubprocess} } diff --git a/src/getIndex.go b/src/getIndex.go index b564685..6cd912b 100644 --- a/src/getIndex.go +++ b/src/getIndex.go @@ -165,94 +165,3 @@ func isUnhashable(val any) bool { keytype := typeof(val) return keytype == "array" || keytype == "map" } - -func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (any, ArErr) { - var ( - start int = 0 - end any = nil - step int = 1 - ) - { - startval, err := runVal(r.args[0], stack, stacklevel+1) - if err.EXISTS { - return ArObject{}, err - } - if startval == nil { - start = 0 - } else if typeof(startval) != "number" || !startval.(number).IsInt() { - return ArObject{}, ArErr{ - "TypeError", - "slice index must be an integer", - r.line, - r.path, - r.code, - true, - } - } else { - start = int(startval.(number).Num().Int64()) - } - } - if len(r.args) > 1 { - endval, err := runVal(r.args[1], stack, stacklevel+1) - if err.EXISTS { - return ArObject{}, err - } - if endval == nil { - end = m.obj["length"] - } else if typeof(endval) != "number" && !endval.(number).IsInt() { - return ArObject{}, ArErr{ - "TypeError", - "slice ending index must be an integer", - r.line, - r.path, - r.code, - true, - } - } else { - end = int(endval.(number).Num().Int64()) - } - } - if len(r.args) > 2 { - stepval, err := runVal(r.args[2], stack, stacklevel+1) - if err.EXISTS { - return ArObject{}, err - } - if stepval == nil { - step = 1 - } else if typeof(stepval) != "number" && !stepval.(number).IsInt() { - return ArObject{}, ArErr{ - "TypeError", - "slice step must be an integer", - r.line, - r.path, - r.code, - true, - } - } else { - step = int(stepval.(number).Num().Int64()) - } - } - if start < 0 { - start = m.obj["length"].(int) + start - } - if _, ok := end.(int); ok && end.(int) < 0 { - end = m.obj["length"].(int) + end.(int) - } - if end == nil { - return m.obj["__value__"].([]any)[start], ArErr{} - } else if step == 1 { - return ArArray([]any{m.obj["__value__"].([]any)[start:end.(int)]}), ArErr{} - } else { - output := []any{} - if step > 0 { - for i := start; i < end.(int); i += step { - output = append(output, m.obj["__value__"].([]any)[i]) - } - } else { - for i := end.(int) - 1; i >= start; i += step { - output = append(output, m.obj["__value__"].([]any)[i]) - } - } - return ArArray(output), ArErr{} - } -} diff --git a/src/input.go b/src/input.go index 7eae9fc..6682441 100644 --- a/src/input.go +++ b/src/input.go @@ -42,11 +42,11 @@ func getPassword(args ...any) (string, error) { break } if char[0] == 3 || char[0] == 4 { - return "", fmt.Errorf("User cancelled") + return "", fmt.Errorf("keyboard interupt") } else if char[0] == '\r' || char[0] == '\n' { fmt.Println() break - } else if char[0] == '\b' { + } else if char[0] == '\b' || char[0] == 127 { if len(password) > 0 { password = password[:len(password)-1] fmt.Print("\b \b") diff --git a/src/string.go b/src/string.go index 7bded14..759d1f9 100644 --- a/src/string.go +++ b/src/string.go @@ -4,6 +4,9 @@ import ( "fmt" "strconv" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) var stringCompile = makeRegex("(( *)\"((\\\\([a-z\\\"'`]))|[^\\\"])*\"( *))|(( *)'((\\\\([a-z\\'\"`]))|[^\\'])*'( *))") @@ -88,7 +91,7 @@ func ArString(str string) ArObject { // a[0] is start // a[1] is end // a[2] is step - if len(a) < 0 || len(a) > 3 { + if len(a) > 3 { return nil, ArErr{"TypeError", "expected 1 to 3 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true} } var ( @@ -265,7 +268,7 @@ func ArString(str string) ArObject { if len(a) != 0 { return nil, ArErr{"TypeError", "expected 0 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true} } - return strings.Title(str), ArErr{} + return cases.Title(language.English).String(str), ArErr{} }} obj.obj["lower"] = builtinFunc{ "lower", diff --git a/src/subprocess.go b/src/subprocess.go new file mode 100644 index 0000000..c8573ff --- /dev/null +++ b/src/subprocess.go @@ -0,0 +1,139 @@ +package main + +import ( + "bufio" + "fmt" + "os/exec" +) + +func ArSubprocess(args ...any) (any, ArErr) { + if len(args) != 1 { + return nil, ArErr{ + TYPE: "RuntimeError", + message: fmt.Sprintf("subprocess() takes exactly 1 argument (%d given)", len(args)), + EXISTS: true, + } + } else if typeof(args[0]) != "array" { + fmt.Println(args[0]) + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("subprocess() argument must be an array, not %s", typeof(args[0])), + EXISTS: true, + } + } else if len(args[0].([]any)) == 0 { + return nil, ArErr{ + TYPE: "RuntimeError", + message: "subprocess() argument must be an array of strings, not an empty array", + EXISTS: true, + } + } + commandlist := []string{} + for _, x := range args[0].([]any) { + if typeof(x) != "string" { + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("subprocess() argument must be an array of strings, not %s", typeof(x)), + EXISTS: true, + } + } + commandlist = append(commandlist, x.(ArObject).obj["__value__"].(string)) + } + cmd := exec.Command(commandlist[0], commandlist[1:]...) + return Map( + anymap{ + "stdout": builtinFunc{ + "output", + func(args ...any) (any, ArErr) { + stdout, err := cmd.StdoutPipe() + + if err != nil { + return nil, ArErr{ + TYPE: "RuntimeError", + message: err.Error(), + EXISTS: true, + } + } + + if err := cmd.Start(); err != nil { + return nil, ArErr{ + TYPE: "RuntimeError", + message: err.Error(), + EXISTS: true, + } + } + scanner := bufio.NewScanner(stdout) // create a new scanner to read the output + scanner.Split(bufio.ScanRunes) + return Map(anymap{ + "scan": builtinFunc{ + "scan", + func(args ...any) (any, ArErr) { + if len(args) != 0 { + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("scan() takes exactly 0 arguments (%d given)", len(args)), + EXISTS: true, + } + } + return scanner.Scan(), ArErr{} + }}, + "text": builtinFunc{ + "text", + func(args ...any) (any, ArErr) { + if len(args) != 0 { + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("text() takes exactly 0 arguments (%d given)", len(args)), + EXISTS: true, + } + } + return scanner.Text(), ArErr{} + }}, + "err": builtinFunc{ + "err", + func(args ...any) (any, ArErr) { + if len(args) != 0 { + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("err() takes exactly 0 arguments (%d given)", len(args)), + EXISTS: true, + } + } + if err := scanner.Err(); err != nil { + return err.Error(), ArErr{} + } + return nil, ArErr{} + }}, + "wait": builtinFunc{ + "wait", + func(args ...any) (any, ArErr) { + if len(args) != 0 { + return nil, ArErr{ + TYPE: "TypeError", + message: fmt.Sprintf("wait() takes exactly 0 arguments (%d given)", len(args)), + EXISTS: true, + } + } + if err := cmd.Wait(); err != nil { + return err.Error(), ArErr{} + } + return nil, ArErr{} + }, + }, + }), ArErr{} + }}, + "output": builtinFunc{ + "output", + func(args ...any) (any, ArErr) { + out, err := cmd.Output() + if err != nil { + return nil, ArErr{ + TYPE: "RuntimeError", + message: err.Error(), + EXISTS: true, + } + } + return string(out), ArErr{} + }}, + }, + ), ArErr{} +} diff --git a/src/term-class.go b/src/term-class.go index f2c02bb..618185d 100644 --- a/src/term-class.go +++ b/src/term-class.go @@ -7,33 +7,6 @@ import ( var timing = anymap{} -var plain = Map(anymap{ - "log": builtinFunc{"log", func(args ...any) (any, ArErr) { - output := []any{} - for i := 0; i < len(args); i++ { - output = append(output, anyToArgon(args[i], false, true, 3, 0, false, 0)) - } - fmt.Println(output...) - return nil, ArErr{} - }}, - "logVal": builtinFunc{"logVal", func(args ...any) (any, ArErr) { - output := []any{} - for i := 0; i < len(args); i++ { - output = append(output, anyToArgon(args[i], true, true, 3, 0, false, 0)) - } - fmt.Println(output...) - return nil, ArErr{} - }}, - "print": builtinFunc{"print", func(args ...any) (any, ArErr) { - output := []any{} - for i := 0; i < len(args); i++ { - output = append(output, anyToArgon(args[i], false, false, 3, 0, false, 0)) - } - fmt.Println(output...) - return nil, ArErr{} - }}, -}) - var ArTerm = Map(anymap{ "log": builtinFunc{"log", func(args ...any) (any, ArErr) { output := []any{} @@ -59,7 +32,40 @@ var ArTerm = Map(anymap{ fmt.Println(output...) return nil, ArErr{} }}, - "plain": plain, + "plain": Map(anymap{ + "log": builtinFunc{"log", func(args ...any) (any, ArErr) { + output := []any{} + for i := 0; i < len(args); i++ { + output = append(output, anyToArgon(args[i], false, true, 3, 0, false, 0)) + } + fmt.Println(output...) + return nil, ArErr{} + }}, + "logVal": builtinFunc{"logVal", func(args ...any) (any, ArErr) { + output := []any{} + for i := 0; i < len(args); i++ { + output = append(output, anyToArgon(args[i], true, true, 3, 0, false, 0)) + } + fmt.Println(output...) + return nil, ArErr{} + }}, + "print": builtinFunc{"print", func(args ...any) (any, ArErr) { + output := []any{} + for i := 0; i < len(args); i++ { + output = append(output, anyToArgon(args[i], false, false, 3, 0, false, 0)) + } + fmt.Println(output...) + return nil, ArErr{} + }}, + "oneLine": builtinFunc{"oneLine", func(args ...any) (any, ArErr) { + output := []any{} + for i := 0; i < len(args); i++ { + output = append(output, anyToArgon(args[i], false, false, 3, 0, false, 0)) + } + fmt.Print(output...) + return nil, ArErr{} + }}, + }), "error": builtinFunc{"error", func(args ...any) (any, ArErr) { output := []any{"error: "} for i := 0; i < len(args); i++ { @@ -103,4 +109,18 @@ var ArTerm = Map(anymap{ fmt.Printf("\x1b[%dm%s\x1b[0m", 34, fmt.Sprint(anyToArgon(id, false, true, 3, 0, false, 0), ": ", timesince)+"\n") return nil, ArErr{} }}, + "input": Map( + anymap{ + "password": builtinFunc{"password", func(args ...any) (any, ArErr) { + resp, err := getPassword(args...) + if err != nil { + return nil, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + return ArString(resp), ArErr{} + }}, + "__call__": builtinFunc{"input", func(args ...any) (any, ArErr) { + return input(args...), ArErr{} + }}, + }, + ), }) diff --git a/src/typeof.go b/src/typeof.go index c835be4..fedeec6 100644 --- a/src/typeof.go +++ b/src/typeof.go @@ -1,7 +1,7 @@ package main func typeof(val any) string { - switch val.(type) { + switch x := val.(type) { case number: return "number" case nil: @@ -10,14 +10,14 @@ func typeof(val any) string { return "boolean" case string: return "string" - case anymap: + case []any: return "array" case Callable: return "function" case builtinFunc: return "function" case ArObject: - return "map" + return x.TYPE case accessVariable: return "variable" }