From 2e04bb01527e495880125fb25c5fa9fb6a33bd89 Mon Sep 17 00:00:00 2001 From: Ugric Date: Sun, 19 Mar 2023 01:10:23 +0000 Subject: [PATCH] make strings object --- example.ar | 11 +++-- go.mod | 7 ++- go.sum | 10 +++++ makerandom.ar | 10 +++++ modules/this.ar | 53 +++++++++++++++++++++++ spec.md | 10 ++--- src/array.go | 90 +++++++++++++++++++++++++++++++-------- src/arvalid.go | 30 +++++++++++++ src/built-in-functions.go | 10 ++++- src/built-ins.go | 19 ++------- src/call.go | 4 ++ src/comment.go | 5 ++- src/file.go | 87 ++++++++++++++++++++++++++++++++++--- src/getIndex.go | 29 ++++--------- src/input.go | 41 ++++++++++++++++++ src/json.go | 21 +++------ src/logarithms.go | 2 +- src/map.go | 25 +++++++++++ src/operations.go | 38 ++++++++--------- src/run.go | 4 +- src/sortany.go | 86 +++++++++++++++++++++++++++++++++++++ src/string.go | 29 +++++++++++++ src/time.go | 2 +- src/to-argon.go | 14 +++--- src/typeof.go | 11 +++-- src/variable.go | 4 +- 26 files changed, 528 insertions(+), 124 deletions(-) create mode 100644 makerandom.ar create mode 100644 modules/this.ar create mode 100644 src/arvalid.go create mode 100644 src/sortany.go diff --git a/example.ar b/example.ar index a6994d7..97fb867 100644 --- a/example.ar +++ b/example.ar @@ -1,5 +1,8 @@ -x = map() -x.poo = 10 +let password = do + let password = passwordInput("set password: ") + while (password.length < 8) do + term.log("password must be longer then 8 characters!") + password = passwordInput("set password: ") + return password -y = [x,x,x] -term.log(y) \ No newline at end of file +term.log("your password is", password) \ No newline at end of file diff --git a/go.mod b/go.mod index 07656db..38f4516 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,9 @@ require ( github.com/jwalton/go-supportscolor v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // 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 ) diff --git a/go.sum b/go.sum index 88ecf7d..90925f9 100644 --- a/go.sum +++ b/go.sum @@ -9,10 +9,20 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/wadey/go-rounding v1.1.0 h1:RAs9dMkB/uUHFv9ljlbRFC8/kBrQ5jhwt1GQq+2cciY= github.com/wadey/go-rounding v1.1.0/go.mod h1:/uD953tCL6Fea2Yp+LZBBp8d60QSObkMJxY6SPOJ5QE= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= diff --git a/makerandom.ar b/makerandom.ar new file mode 100644 index 0000000..b9af17b --- /dev/null +++ b/makerandom.ar @@ -0,0 +1,10 @@ +y = [] +i = 0 +while (i<1000000) do + y.append(random()) + if (i % 100000 == 0) term.log(i) + i = i + 1 + +term.time("write") +open("array.json", "w").json(y) +term.timeEnd("write") \ No newline at end of file diff --git a/modules/this.ar b/modules/this.ar new file mode 100644 index 0000000..fd64d4e --- /dev/null +++ b/modules/this.ar @@ -0,0 +1,53 @@ +# The Argon Manifesto - ChatGPT + +# Simple is better than complex +# Argon's design, we should respect +# Readability is key, it's plain to see +# With Argon, code clarity comes naturally + +# Sparse is better than dense +# Argon's syntax, it makes sense +# No need for excess, or verbosity +# With Argon, brevity is a necessity + +# Explicit is better than implicit +# Argon's logic, it's not cryptic +# Avoiding confusion, it's a must +# With Argon, understanding is a trust + +# Errors should never pass silently +# Argon catches them, and does so quietly +# Graceful handling, it's what we aim to achieve +# With Argon, bugs are easier to perceive + +# That which is complex, can be made simple +# Argon's power, it's in its example +# Programming, it can be a breeze +# With Argon, it's a language that's sure to please + +term.log("The Argon Manifesto - ChatGPT") +term.log() +term.log("Simple is better than complex") +term.log("Argon's design, we should respect") +term.log("Readability is key, it's plain to see") +term.log("With Argon, code clarity comes naturally") +term.log() +term.log("Sparse is better than dense") +term.log("Argon's syntax, it makes sense") +term.log("No need for excess, or verbosity") +term.log("With Argon, brevity is a necessity") +term.log() +term.log("Explicit is better than implicit") +term.log("Argon's logic, it's not cryptic") +term.log("Avoiding confusion, it's a must") +term.log("With Argon, understanding is a trust") +term.log() +term.log("Errors should never pass silently") +term.log("Argon catches them, and does so quietly") +term.log("Graceful handling, it's what we aim to achieve") +term.log("With Argon, bugs are easier to perceive") +term.log() +term.log("That which is complex, can be made simple") +term.log("Argon's power, it's in its example") +term.log("Programming, it can be a breeze") +term.log("With Argon, it's a language that's sure to please") \ No newline at end of file diff --git a/spec.md b/spec.md index 8879733..582505b 100644 --- a/spec.md +++ b/spec.md @@ -37,7 +37,7 @@ setting variables returns the value, which can be used. example: ```javascript -if (x = 10) > 5 do +if ((x = 10) > 5) do term.log(x, 'is bigger than 5') ``` @@ -98,10 +98,10 @@ example: ```javascript let password = do - let password = input("set password: ") - while len(password) < 8 do - log("password must be longer then 8 characters!") - password = input("set password: ") + let password = passwordInput("set password: ") + while (password.length < 8) do + term.log("password must be longer then 8 characters!") + password = passwordInput("set password: ") return password term.log("your password is", password) diff --git a/src/array.go b/src/array.go index 21fab8b..2c82f25 100644 --- a/src/array.go +++ b/src/array.go @@ -1,6 +1,8 @@ package main -import "strings" +import ( + "strings" +) var arrayCompile = makeRegex(`( *)\[(.|\n)*\]( *)`) @@ -20,7 +22,7 @@ func ArArray(arr []any) ArObject { "array", anymap{ "__value__": arr, - "length": len(arr), + "length": newNumber().SetUint64(uint64(len(arr))), }, } val.obj["remove"] = builtinFunc{ @@ -56,7 +58,7 @@ func ArArray(arr []any) ArObject { } } arr = append(arr[:num], arr[num+1:]...) - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return nil, ArErr{} }} @@ -71,7 +73,7 @@ func ArArray(arr []any) ArObject { } } arr = append(arr, args...) - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return nil, ArErr{} }, @@ -109,7 +111,7 @@ func ArArray(arr []any) ArObject { } } arr = append(arr[:num], append(args[1:], arr[num:]...)...) - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return nil, ArErr{} }, @@ -149,13 +151,13 @@ func ArArray(arr []any) ArObject { } v := arr[num] arr = append(arr[:num], arr[num+1:]...) - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return v, ArErr{} } v := arr[len(arr)-1] arr = arr[:len(arr)-1] - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return v, ArErr{} }, @@ -171,7 +173,7 @@ func ArArray(arr []any) ArObject { } } arr = []any{} - val.obj["length"] = len(arr) + val.obj["length"] = newNumber().SetUint64(uint64(len(arr))) val.obj["__value__"] = arr return nil, ArErr{} }, @@ -199,6 +201,66 @@ func ArArray(arr []any) ArObject { return nil, ArErr{} }, } + val.obj["sort"] = builtinFunc{ + "sort", + func(args ...any) (any, ArErr) { + if len(args) > 2 { + return nil, ArErr{ + TYPE: "TypeError", + message: "too many arguments", + EXISTS: true, + } + } + reverse := false + if len(args) >= 1 { + if typeof(args[0]) != "boolean" { + return nil, ArErr{ + TYPE: "TypeError", + message: "argument must be a boolean", + EXISTS: true, + } + } + reverse = args[0].(bool) + } + if len(args) == 2 { + if typeof(args[1]) != "function" { + return nil, ArErr{ + TYPE: "TypeError", + message: "argument must be a function", + EXISTS: true, + } + } + output, err := quickSort(arr, func(a any) (any, ArErr) { + return runCall(call{ + args[1], + []any{a}, "", 0, "", + }, stack{vars, newscope()}, 0) + }) + if err.EXISTS { + return nil, err + } + arr = output + val.obj["length"] = len(arr) + val.obj["__value__"] = arr + return nil, ArErr{} + } + output, err := quickSort(arr, func(a any) (any, ArErr) { + return a, ArErr{} + }) + if err.EXISTS { + return nil, err + } + if reverse { + for i, j := 0, len(output)-1; i < j; i, j = i+1, j-1 { + output[i], output[j] = output[j], output[i] + } + } + arr = output + val.obj["length"] = len(arr) + val.obj["__value__"] = arr + return nil, ArErr{} + }, + } val.obj["map"] = builtinFunc{ "map", func(args ...any) (any, ArErr) { @@ -320,6 +382,7 @@ func ArArray(arr []any) ArObject { } output := []string{} for _, v := range arr { + v = ArValidToAny(v) if typeof(v) != "string" { return nil, ArErr{ TYPE: "TypeError", @@ -329,7 +392,7 @@ func ArArray(arr []any) ArObject { } output = append(output, v.(string)) } - return strings.Join(output, args[0].(string)), ArErr{} + return ArString(strings.Join(output, args[0].(string))), ArErr{} }, } val.obj["concat"] = builtinFunc{ @@ -356,15 +419,6 @@ func ArArray(arr []any) ArObject { return val } -func potentialAnyArrayToArArray(arr any) any { - switch arr := arr.(type) { - case []any: - return ArArray(arr) - default: - return arr - } -} - func parseArray(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { trimmed := strings.TrimSpace(code.code) trimmed = trimmed[1 : len(trimmed)-1] diff --git a/src/arvalid.go b/src/arvalid.go new file mode 100644 index 0000000..298bccd --- /dev/null +++ b/src/arvalid.go @@ -0,0 +1,30 @@ +package main + +func AnyToArValid(arr any) any { + switch arr := arr.(type) { + case []any: + return ArArray(arr) + case string: + return ArString(arr) + default: + return arr + } +} + +func ArValidToAny(a any) any { + switch a := a.(type) { + case ArObject: + switch a.TYPE { + case "string": + return a.obj["__value__"] + case "array": + return a.obj["__value__"] + case "class": + return a.obj["__value__"] + default: + return a.obj + } + default: + return a + } +} diff --git a/src/built-in-functions.go b/src/built-in-functions.go index 07955d9..d3b19ed 100644 --- a/src/built-in-functions.go +++ b/src/built-in-functions.go @@ -10,9 +10,15 @@ type builtinFunc struct { } func ArgonString(args ...any) (any, ArErr) { - return anyToArgon(args[0], true, false, 3, 0, false, 0), 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{} } diff --git a/src/built-ins.go b/src/built-ins.go index 89b306d..11f975b 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -6,21 +6,10 @@ 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 - vars.obj["length"] = builtinFunc{"length", func(a ...any) (any, ArErr) { - switch x := a[0].(type) { - case string: - return len(x), ArErr{} - case ArObject: - if x.TYPE == "array" { - return len(x.obj["__value__"].([]any)), ArErr{} - } - return len(x.obj), ArErr{} - } - return nil, ArErr{TYPE: "TypeError", message: "Cannot get length of " + typeof(a[0]), EXISTS: true} - }} vars.obj["map"] = builtinFunc{"map", func(a ...any) (any, ArErr) { if len(a) == 0 { return Map(anymap{}), ArErr{} @@ -48,7 +37,7 @@ func init() { case string: newmap := anymap{} for i, v := range x { - newmap[i] = string(v) + newmap[i] = ArString(string(v)) } return Map(newmap), ArErr{} } @@ -62,7 +51,7 @@ func init() { case string: newarray := []any{} for _, v := range x { - newarray = append(newarray, string(v)) + newarray = append(newarray, ArString(string(v))) } return ArArray(newarray), ArErr{} case ArObject: @@ -139,7 +128,7 @@ func init() { return nil, ArErr{TYPE: "TypeError", message: "Cannot ceil '" + typeof(a[0]) + "'", EXISTS: true} }} vars.obj["sqrt"] = builtinFunc{"sqrt", ArgonSqrt} - vars.obj["file"] = ArFile + vars.obj["open"] = builtinFunc{"open", ArOpen} vars.obj["random"] = ArRandom vars.obj["json"] = ArJSON vars.obj["sin"] = ArSin diff --git a/src/call.go b/src/call.go index b0609e4..1d0425c 100644 --- a/src/call.go +++ b/src/call.go @@ -92,7 +92,11 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) { } switch x := callable.(type) { case builtinFunc: + for i := range args { + args[i] = ArValidToAny(args[i]) + } resp, err := x.FUNC(args...) + resp = AnyToArValid(resp) if err.EXISTS { if err.line == 0 { err.line = c.line diff --git a/src/comment.go b/src/comment.go index 8dd2551..ef44e89 100644 --- a/src/comment.go +++ b/src/comment.go @@ -21,7 +21,10 @@ func parseComment(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bo for i := 0; i < len(split)-1; i++ { temp = append(temp, split[i]) joined := strings.Join(temp, "#") - resp, worked, _, s := translateVal(UNPARSEcode{code: joined, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, 0) + if isBlank(UNPARSEcode{code: joined, realcode: code.realcode, line: code.line, path: code.path}) { + return nil, true, ArErr{}, step + } + resp, worked, _, s := translateVal(UNPARSEcode{code: joined, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, 2) step += s - 1 if worked { return resp, true, ArErr{}, step diff --git a/src/file.go b/src/file.go index b69ef2f..7174124 100644 --- a/src/file.go +++ b/src/file.go @@ -7,10 +7,87 @@ import ( "os" ) -var ArFile = Map(anymap{ - "read": builtinFunc{"read", ArRead}, - "write": builtinFunc{"write", ArWrite}, -}) +func ArOpen(args ...any) (any, ArErr) { + if len(args) > 2 { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "open takes 1 or 2 argument, got " + fmt.Sprint(len(args)), EXISTS: true} + } + if typeof(args[0]) != "string" { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "open takes a string not type '" + typeof(args[0]) + "'", EXISTS: true} + } + path := args[0].(string) + mode := "r" + if len(args) == 2 { + if typeof(args[1]) != "string" { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "open takes a string not type '" + typeof(args[1]) + "'", EXISTS: true} + } + mode = args[1].(string) + } + if mode != "r" && mode != "w" { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "open mode must be 'r', or 'w'", EXISTS: true} + } + if mode == "r" { + file, err := os.Open(path) + if err != nil { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + return Map(anymap{ + "text": builtinFunc{"text", func(...any) (any, ArErr) { + text, err := readtext(file) + if err != nil { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + return ArString(text), ArErr{} + }, + }, + "json": builtinFunc{"json", func(...any) (any, ArErr) { + text, err := readtext(file) + if err != nil { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + return jsonparse(text), ArErr{} + }, + }, + }), ArErr{} + } + file, err := os.Create(path) + if err != nil { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + return Map(anymap{ + "text": builtinFunc{"text", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "text takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true} + } + if typeof(args[0]) != "string" { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "text takes a string not type '" + typeof(args[0]) + "'", EXISTS: true} + } + file.Write([]byte(args[0].(string))) + return nil, ArErr{} + }}, + "json": builtinFunc{"json", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "json takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true} + } + jsonstr, err := jsonstringify(args[0], 0) + if err != nil { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} + } + file.Write([]byte(jsonstr)) + return nil, ArErr{} + }}, + "append": builtinFunc{"append", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "append takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true} + } + if typeof(args[0]) != "string" { + return ArObject{}, ArErr{TYPE: "Runtime Error", message: "append takes a string not type '" + typeof(args[0]) + "'", EXISTS: true} + } + file.Write([]byte(args[0].(string))) + return nil, ArErr{} + }}, + }), ArErr{} + +} func readtext(file *os.File) (string, error) { var buf bytes.Buffer @@ -39,7 +116,7 @@ func ArRead(args ...any) (any, ArErr) { if err != nil { return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} } - return text, ArErr{} + return ArString(text), ArErr{} }}, "json": builtinFunc{"json", func(...any) (any, ArErr) { text, err := readtext(file) diff --git a/src/getIndex.go b/src/getIndex.go index df9f3bf..06dbbb4 100644 --- a/src/getIndex.go +++ b/src/getIndex.go @@ -37,6 +37,11 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) { if !err.EXISTS { return resp, err } + case "string": + resp, err := getFromString(m.obj["__value__"].(string), r, stack, stacklevel+1) + if !err.EXISTS { + return ArString(resp), err + } } if len(r.args) > 1 { return nil, ArErr{ @@ -52,6 +57,7 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) { if err.EXISTS { return nil, err } + key = ArValidToAny(key) if isUnhashable(key) { return nil, ArErr{ "TypeError", @@ -72,15 +78,7 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) { true, } } - return potentialAnyArrayToArArray(m.obj[key]), ArErr{} - case string: - if val, ok := r.args[0].(string); !r.index && ok { - switch val { - case "length": - return len(m), ArErr{} - } - } - return getFromString(m, r, stack, stacklevel+1) + return AnyToArValid(m.obj[key]), ArErr{} } key, err := runVal(r.args[0], stack, stacklevel+1) @@ -97,15 +95,6 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) { } } -func classVal(r any) any { - if j, ok := r.(ArObject); ok { - if _, ok := j.obj["__value__"]; ok { - return j.obj["__value__"] - } - } - return r -} - func isMapGet(code UNPARSEcode) bool { return mapGetCompile.MatchString(code.code) } @@ -174,7 +163,7 @@ func isUnhashable(val any) bool { return keytype == "array" || keytype == "map" } -func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (ArObject, ArErr) { +func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (any, ArErr) { var ( start int = 0 end any = nil @@ -247,7 +236,7 @@ func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (ArObje end = m.obj["length"].(int) + end.(int) } if end == nil { - return ArArray([]any{m.obj["__value__"].([]any)[start]}), ArErr{} + return m.obj["__value__"].([]any)[start], ArErr{} } else if step == 1 { return ArArray([]any{m.obj["__value__"].([]any)[start:end.(int)]}), ArErr{} } else { diff --git a/src/input.go b/src/input.go index d4194f4..7eae9fc 100644 --- a/src/input.go +++ b/src/input.go @@ -4,6 +4,8 @@ import ( "bufio" "fmt" "os" + + "golang.org/x/term" ) func input(args ...any) string { @@ -17,3 +19,42 @@ func input(args ...any) string { input := scanner.Text() return input } + +func getPassword(args ...any) (string, error) { + output := []any{} + for i := 0; i < len(args); i++ { + output = append(output, anyToArgon(args[i], false, true, 3, 0, true, 0)) + } + fmt.Print(output...) + password := []byte{} + + oldState, err := term.MakeRaw(int(os.Stdin.Fd())) + if err != nil { + panic(err) + } + defer term.Restore(int(os.Stdin.Fd()), oldState) + + for { + char := make([]byte, 1) + _, err := os.Stdin.Read(char) + if err != nil { + fmt.Println(err) + break + } + if char[0] == 3 || char[0] == 4 { + return "", fmt.Errorf("User cancelled") + } else if char[0] == '\r' || char[0] == '\n' { + fmt.Println() + break + } else if char[0] == '\b' { + if len(password) > 0 { + password = password[:len(password)-1] + fmt.Print("\b \b") + } + } else { + password = append(password, char[0]) + fmt.Print("*") + } + } + return string(password), nil +} diff --git a/src/json.go b/src/json.go index d60c6c2..0336f75 100644 --- a/src/json.go +++ b/src/json.go @@ -11,12 +11,15 @@ import ( func convertToArgon(obj any) any { switch x := obj.(type) { case map[string]interface{}: - newmap := Map(anymap{}) + newmap := anymap{} for key, value := range x { - newmap.obj[key] = convertToArgon(value) + newmap[key] = convertToArgon(value) } - return newmap + return Map(newmap) case []any: + for i, value := range x { + x[i] = convertToArgon(value) + } return ArArray(x) case string: return x @@ -41,19 +44,9 @@ func jsonstringify(obj any, level int) (string, error) { return "", errors.New("json stringify error: too many levels") } output := []string{} - obj = classVal(obj) + obj = ArValidToAny(obj) switch x := obj.(type) { case ArObject: - if x.TYPE == "array" { - for _, value := range x.obj["__value__"].([]any) { - str, err := jsonstringify(value, level+1) - if err != nil { - return "", err - } - output = append(output, str) - } - return "[" + strings.Join(output, ", ") + "]", nil - } for key, value := range x.obj { str, err := jsonstringify(value, level+1) if err != nil { diff --git a/src/logarithms.go b/src/logarithms.go index ef028da..65b5721 100644 --- a/src/logarithms.go +++ b/src/logarithms.go @@ -5,7 +5,7 @@ import ( "math" ) -var N = newNumber().SetInt64(1e10) +var N = newNumber().SetInt64(1e6) func Ln(x number) number { output := newNumber() diff --git a/src/map.go b/src/map.go index 1992345..248e5d7 100644 --- a/src/map.go +++ b/src/map.go @@ -1,8 +1,33 @@ package main +import ( + "fmt" + "strings" +) + +var mapCompiled = makeRegex(`( *)\{(((( *).+( *):( *).+( *))|(` + spacelessVariable + `))(( *)\,(( *).+( *):( *).+( *))|(` + spacelessVariable + `)))*\}( *)`) + +func isMap(code UNPARSEcode) bool { + return mapCompiled.MatchString(code.code) +} + +func parseMap(code UNPARSEcode) (any, UNPARSEcode) { + trimmed := strings.Trim(code.code, " ") + trimmed = trimmed[1 : len(trimmed)-1] + fmt.Println(trimmed) + return nil, UNPARSEcode{} +} + func Map(val anymap) ArObject { return ArObject{ TYPE: "map", obj: val, } } + +func Class(val anymap) ArObject { + return ArObject{ + TYPE: "class", + obj: val, + } +} diff --git a/src/operations.go b/src/operations.go index 388df97..36a0526 100644 --- a/src/operations.go +++ b/src/operations.go @@ -121,7 +121,7 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return false, err } @@ -131,7 +131,7 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp2 = classVal(resp2) + resp2 = ArValidToAny(resp2) if err.EXISTS { return false, err } @@ -207,7 +207,7 @@ func calcNegative(o operationType, stack stack, stacklevel int) (number, ArErr) stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -228,7 +228,7 @@ func calcNegative(o operationType, stack stack, stacklevel int) (number, ArErr) stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -255,7 +255,7 @@ func calcDivide(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -276,7 +276,7 @@ func calcDivide(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -303,7 +303,7 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -319,7 +319,7 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -333,7 +333,7 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { } } - return output, ArErr{} + return AnyToArValid(output), ArErr{} } func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { @@ -343,7 +343,7 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -359,7 +359,7 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -393,7 +393,7 @@ func calcAnd(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -413,7 +413,7 @@ func calcOr(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -450,7 +450,7 @@ func calcIn(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return false, err } @@ -460,7 +460,7 @@ func calcIn(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp2 = classVal(resp2) + resp2 = ArValidToAny(resp2) if err.EXISTS { return false, err } @@ -501,7 +501,7 @@ func calcMod(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -522,7 +522,7 @@ func calcMod(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -557,7 +557,7 @@ func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -578,7 +578,7 @@ func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { stack, stacklevel+1, ) - resp = classVal(resp) + resp = ArValidToAny(resp) if err.EXISTS { return nil, err } diff --git a/src/run.go b/src/run.go index 502abcf..764efaa 100644 --- a/src/run.go +++ b/src/run.go @@ -17,7 +17,7 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) { case number: return x, ArErr{} case string: - return x, ArErr{} + return ArString(x), ArErr{} case call: if stackoverflow { linenum = x.line @@ -66,7 +66,7 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) { break } resp, err := runVal(x.VAL, stack, stacklevel+1) - resp = classVal(resp) + resp = AnyToArValid(resp) if err.EXISTS { return nil, err } diff --git a/src/sortany.go b/src/sortany.go new file mode 100644 index 0000000..b9a48aa --- /dev/null +++ b/src/sortany.go @@ -0,0 +1,86 @@ +package main + +import "fmt" + +type keyCache map[interface{}]interface{} + +func quickSort(list []interface{}, getKey func(interface{}) (interface{}, ArErr)) ([]interface{}, ArErr) { + if len(list) <= 1 { + return list, ArErr{} + } + + pivot := list[0] + var left []interface{} + var right []interface{} + + var cache = make(keyCache) + + for _, v := range list[1:] { + val, err := getkeyCache(getKey, v, cache) + if err.EXISTS { + return nil, err + } + pivotval, err := getkeyCache(getKey, pivot, cache) + if err.EXISTS { + return nil, err + } + comp, comperr := compare(val, pivotval) + if comperr != nil { + return nil, ArErr{ + TYPE: "TypeError", + message: comperr.Error(), + EXISTS: true, + } + } + if comp < 0 { + left = append(left, v) + } else { + right = append(right, v) + } + } + + left, err := quickSort(left, getKey) + if err.EXISTS { + return nil, err + } + right, err = quickSort(right, getKey) + if err.EXISTS { + return nil, err + } + + return append(append(left, pivot), right...), ArErr{} +} + +func getkeyCache(getKey func(interface{}) (interface{}, ArErr), index interface{}, cache keyCache) (interface{}, ArErr) { + if cacheval, ok := cache[index]; ok { + return cacheval, ArErr{} + } + val, err := getKey(index) + if err.EXISTS { + return nil, err + } + cache[index] = val + return val, ArErr{} +} + +func compare(a, b interface{}) (int, error) { + switch x := a.(type) { + case string: + if _, ok := b.(string); !ok { + return 0, fmt.Errorf("cannot compare %T to %T", a, b) + } + if a == b { + return 0, nil + } + if x < b.(string) { + return -1, nil + } + return 1, nil + case number: + if _, ok := b.(number); !ok { + return 0, fmt.Errorf("cannot compare %T to %T", a, b) + } + return x.Cmp(b.(number)), nil + } + return 0, fmt.Errorf("cannot compare %T to %T", a, b) +} diff --git a/src/string.go b/src/string.go index 16804d0..794792d 100644 --- a/src/string.go +++ b/src/string.go @@ -41,3 +41,32 @@ func parseString(code UNPARSEcode) (string, bool, ArErr, int) { return unquoted, true, ArErr{}, 1 } + +func ArString(str string) ArObject { + obj := ArObject{ + "string", + anymap{ + "__value__": str, + "length": newNumber().SetUint64(uint64(len(str))), + }, + } + obj.obj["append"] = builtinFunc{ + "append", + func(a ...any) (any, ArErr) { + if len(a) == 0 { + return nil, ArErr{"TypeError", "expected 1 or more argument, got 0", 0, "", "", true} + } + output := []string{str} + for _, v := range a { + if typeof(v) != "string" { + return nil, ArErr{"TypeError", "expected string, got " + typeof(v), 0, "", "", true} + } + output = append(output, v.(string)) + } + str = strings.Join(output, "") + obj.obj["__value__"] = str + obj.obj["length"] = newNumber().SetUint64(uint64(len(str))) + return nil, ArErr{} + }} + return obj +} diff --git a/src/time.go b/src/time.go index 2699bd0..1c1707b 100644 --- a/src/time.go +++ b/src/time.go @@ -7,7 +7,7 @@ import ( var MicroSeconds = newNumber().SetInt64(1000000) func ArTimeClass(N time.Time) ArObject { - return Map(anymap{ + return Class(anymap{ "__value__": newNumber().Quo(newNumber().SetInt64(N.UnixMicro()), MicroSeconds), "year": builtinFunc{ "year", diff --git a/src/to-argon.go b/src/to-argon.go index 0feb80c..2de7e75 100644 --- a/src/to-argon.go +++ b/src/to-argon.go @@ -11,6 +11,7 @@ import ( ) func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored bool, plain int) string { + x = ArValidToAny(x) output := []string{} maybenewline := "" if plain == 1 { @@ -72,17 +73,14 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored if colored { output = append(output, "\x1b[0m") } - case ArObject: - if x.TYPE == "array" { - return anyToArgon(x.obj["__value__"], quote, simplify, depth, indent, colored, plain) - } - if len(x.obj) == 0 { + case anymap: + if len(x) == 0 { return "{}" } - keys := make([]any, len(x.obj)) + keys := make([]any, len(x)) i := 0 - for k := range x.obj { + for k := range x { keys[i] = k i++ } @@ -103,7 +101,7 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored } keyval = strings.Join(outputkeyval, "") } - output = append(output, keyval+": "+anyToArgon(x.obj[key], true, true, depth-1, indent+1, colored, plain)) + output = append(output, keyval+": "+anyToArgon(x[key], true, true, depth-1, indent+1, colored, plain)) } return "{" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "}" case []any: diff --git a/src/typeof.go b/src/typeof.go index ea5be47..c835be4 100644 --- a/src/typeof.go +++ b/src/typeof.go @@ -1,23 +1,22 @@ package main func typeof(val any) string { - switch x := val.(type) { + switch val.(type) { case number: return "number" - case string: - return "string" case nil: return "null" case bool: return "boolean" + case string: + return "string" + case anymap: + return "array" case Callable: return "function" case builtinFunc: return "function" case ArObject: - if x.TYPE == "array" { - return "array" - } return "map" case accessVariable: return "variable" diff --git a/src/variable.go b/src/variable.go index 45d61f8..5b1112d 100644 --- a/src/variable.go +++ b/src/variable.go @@ -5,7 +5,8 @@ import ( "sync" ) -var SpacelessVariableCompiled = makeRegex(`([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*`) +var spacelessVariable = `([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*` +var SpacelessVariableCompiled = makeRegex(spacelessVariable) var variableCompile = makeRegex(`( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`) var validname = makeRegex(`(.|\n)*(\(( *)((([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)(( *)\,( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)*)?( *)\))`) var setVariableCompile = makeRegex(`( *)(let( +))(.|\n)+( *)=(.|\n)+`) @@ -242,6 +243,7 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) { return nil, ArErr{"Runtime Error", "cannot set by slice", v.line, v.path, v.code, true} } key, err := runVal(x.args[0], stack, stacklevel+1) + key = ArValidToAny(key) if err.EXISTS { return nil, err }