make arrays an object

This commit is contained in:
2023-03-15 21:02:00 +00:00
parent b53f2b4a0a
commit 814209c392
24 changed files with 545 additions and 325 deletions

View File

@@ -5,7 +5,7 @@ import "strings"
var arrayCompile = makeRegex(`( *)\[(.|\n)*\]( *)`)
type CreateArray struct {
value ArArray
value []any
line int
code string
path string
@@ -15,6 +15,233 @@ func isArray(code UNPARSEcode) bool {
return arrayCompile.MatchString(code.code)
}
func ArArray(arr []any) ArObject {
val := ArObject{
"array",
anymap{
"__value__": arr,
"length": len(arr),
},
}
val.obj["remove"] = builtinFunc{
"remove",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return nil, ArErr{
TYPE: "TypeError",
message: "missing argument",
EXISTS: true,
}
}
if typeof(args[0]) != "number" {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be a number",
EXISTS: true,
}
}
if !args[0].(number).IsInt() {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be an integer",
EXISTS: true,
}
}
num := int(args[0].(number).Num().Int64())
if num < 0 || num >= len(arr) {
return nil, ArErr{
TYPE: "IndexError",
message: "index out of range",
EXISTS: true,
}
}
arr = append(arr[:num], arr[num+1:]...)
val.obj["length"] = len(arr)
val.obj["__value__"] = arr
return nil, ArErr{}
}}
val.obj["append"] = builtinFunc{
"append",
func(args ...any) (any, ArErr) {
if len(args) == 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "missing argument",
EXISTS: true,
}
}
arr = append(arr, args...)
val.obj["length"] = len(arr)
val.obj["__value__"] = arr
return nil, ArErr{}
},
}
val.obj["insert"] = builtinFunc{
"insert",
func(args ...any) (any, ArErr) {
if len(args) < 2 {
return nil, ArErr{
TYPE: "TypeError",
message: "missing argument",
EXISTS: true,
}
}
if typeof(args[0]) != "number" {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be a number",
EXISTS: true,
}
}
if !args[0].(number).IsInt() {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be an integer",
EXISTS: true,
}
}
num := int(args[0].(number).Num().Int64())
if num < 0 || num > len(arr) {
return nil, ArErr{
TYPE: "IndexError",
message: "index out of range",
EXISTS: true,
}
}
arr = append(arr[:num], append(args[1:], arr[num:]...)...)
val.obj["length"] = len(arr)
val.obj["__value__"] = arr
return nil, ArErr{}
},
}
val.obj["pop"] = builtinFunc{
"pop",
func(args ...any) (any, ArErr) {
if len(args) > 1 {
return nil, ArErr{
TYPE: "TypeError",
message: "too many arguments",
EXISTS: true,
}
}
if len(args) == 1 {
if typeof(args[0]) != "number" {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be a number",
EXISTS: true,
}
}
if !args[0].(number).IsInt() {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be an integer",
EXISTS: true,
}
}
num := int(args[0].(number).Num().Int64())
if num < 0 || num >= len(arr) {
return nil, ArErr{
TYPE: "IndexError",
message: "index out of range",
EXISTS: true,
}
}
v := arr[num]
arr = append(arr[:num], arr[num+1:]...)
val.obj["length"] = 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["__value__"] = arr
return v, ArErr{}
},
}
val.obj["clear"] = builtinFunc{
"clear",
func(args ...any) (any, ArErr) {
if len(args) != 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "too many arguments",
EXISTS: true,
}
}
arr = []any{}
val.obj["length"] = len(arr)
val.obj["__value__"] = arr
return nil, ArErr{}
},
}
val.obj["extend"] = builtinFunc{
"extend",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return nil, ArErr{
TYPE: "TypeError",
message: "missing argument",
EXISTS: true,
}
}
if typeof(args[0]) != "array" {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be an array",
EXISTS: true,
}
}
arr = append(arr, args[0].(ArObject).obj["__value__"].([]any)...)
val.obj["length"] = len(arr)
val.obj["__value__"] = arr
return nil, ArErr{}
},
}
val.obj["map"] = builtinFunc{
"map",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return nil, ArErr{
TYPE: "TypeError",
message: "missing argument",
EXISTS: true,
}
}
if typeof(args[0]) != "function" {
return nil, ArErr{
TYPE: "TypeError",
message: "argument must be a function",
EXISTS: true,
}
}
newarr := []any{}
for _, v := range arr {
vv, err := runCall(call{
args[0],
[]any{v}, "", 0, "",
}, stack{vars, newscope()}, 0)
if err.EXISTS {
return nil, err
}
newarr = append(newarr, vv)
}
return ArArray(newarr), ArErr{}
},
}
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]
@@ -27,14 +254,14 @@ func parseArray(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool
}, worked, err, 1
}
func runArray(a CreateArray, stack stack, stacklevel int) ([]any, ArErr) {
var array ArArray
func runArray(a CreateArray, stack stack, stacklevel int) (ArObject, ArErr) {
var array []any
for _, val := range a.value {
val, err := runVal(val, stack, stacklevel+1)
if err.EXISTS {
return nil, err
return ArObject{}, err
}
array = append(array, val)
}
return array, ArErr{}
return ArArray(array), ArErr{}
}

View File

@@ -12,8 +12,11 @@ func anyToBool(x any) bool {
return x
case nil:
return false
case ArMap:
return len(x) != 0
case ArObject:
if x.TYPE == "array" {
return len(x.obj["__value__"].([]any)) != 0
}
return len(x.obj) != 0
case builtinFunc:
return true
case Callable:

View File

@@ -1,97 +1,97 @@
package main
import (
"fmt"
"strings"
)
var vars = scope{}
var vars = Map(anymap{})
func init() {
vars["global"] = vars
vars["term"] = ArTerm
vars["input"] = builtinFunc{"input", ArgonInput}
vars["number"] = builtinFunc{"number", ArgonNumber}
vars["string"] = builtinFunc{"string", ArgonString}
vars["infinity"] = infinity
vars["length"] = builtinFunc{"length", func(a ...any) (any, ArErr) {
vars.obj["global"] = vars
vars.obj["term"] = ArTerm
vars.obj["input"] = builtinFunc{"input", ArgonInput}
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 ArMap:
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["map"] = builtinFunc{"map", func(a ...any) (any, ArErr) {
vars.obj["map"] = builtinFunc{"map", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return ArMap{}, ArErr{}
return Map(anymap{}), ArErr{}
}
switch x := a[0].(type) {
case ArMap:
case ArObject:
if x.TYPE == "array" {
newmap := anymap{}
for i, v := range x.obj["__value__"].([]any) {
switch y := v.(type) {
case []any:
if len(y) == 2 {
if isUnhashable(y[0]) {
return nil, ArErr{TYPE: "TypeError", message: "Cannot use unhashable value as key: " + typeof(y[0]), EXISTS: true}
}
newmap[y[0]] = y[1]
continue
}
}
newmap[i] = v
}
return Map(newmap), ArErr{}
}
return x, ArErr{}
case string:
newmap := ArMap{}
newmap := anymap{}
for i, v := range x {
newmap[i] = string(v)
}
return newmap, ArErr{}
case ArArray:
newmap := ArMap{}
for i, v := range x {
switch y := v.(type) {
case ArArray:
if len(y) == 2 {
if isUnhashable(y[0]) {
return nil, ArErr{TYPE: "TypeError", message: "Cannot use unhashable value as key: " + typeof(y[0]), EXISTS: true}
}
newmap[y[0]] = y[1]
continue
}
}
newmap[i] = v
}
return newmap, ArErr{}
return Map(newmap), ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot create map from '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["array"] = builtinFunc{"array", func(a ...any) (any, ArErr) {
vars.obj["array"] = builtinFunc{"array", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return ArArray{}, ArErr{}
return ArArray([]any{}), ArErr{}
}
switch x := a[0].(type) {
case ArArray:
return x, ArErr{}
case string:
newarray := ArArray{}
newarray := []any{}
for _, v := range x {
newarray = append(newarray, string(v))
}
return newarray, ArErr{}
case ArMap:
newarray := ArArray{}
for key, val := range x {
newarray = append(newarray, ArArray{key, val})
return ArArray(newarray), ArErr{}
case ArObject:
if x.TYPE == "array" {
return x, ArErr{}
}
return newarray, ArErr{}
newarray := []any{}
for key, val := range x.obj {
newarray = append(newarray, []any{key, val})
}
return ArArray(newarray), ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot create array from '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["boolean"] = builtinFunc{"boolean", func(a ...any) (any, ArErr) {
vars.obj["boolean"] = builtinFunc{"boolean", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return false, ArErr{}
}
return anyToBool(a[0]), ArErr{}
}}
vars["time"] = ArTime
vars["PI"] = PI
vars["π"] = PI
vars["e"] = e
vars["ln"] = builtinFunc{"ln", ArgonLn}
vars["log"] = builtinFunc{"log", ArgonLog}
vars["logN"] = builtinFunc{"logN", ArgonLogN}
vars["thread"] = builtinFunc{"thread", ArThread}
vars["round"] = builtinFunc{"round", func(a ...any) (any, ArErr) {
vars.obj["time"] = ArTime
vars.obj["PI"] = PI
vars.obj["π"] = PI
vars.obj["e"] = e
vars.obj["ln"] = builtinFunc{"ln", ArgonLn}
vars.obj["log"] = builtinFunc{"log", ArgonLog}
vars.obj["logN"] = builtinFunc{"logN", ArgonLogN}
vars.obj["thread"] = builtinFunc{"thread", ArThread}
vars.obj["round"] = builtinFunc{"round", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{TYPE: "round", message: "round takes 1 argument",
EXISTS: true}
@@ -115,7 +115,7 @@ func init() {
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot round '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["floor"] = builtinFunc{"floor", func(a ...any) (any, ArErr) {
vars.obj["floor"] = builtinFunc{"floor", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{TYPE: "floor", message: "floor takes 1 argument",
EXISTS: true}
@@ -126,7 +126,7 @@ func init() {
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot floor '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["ceil"] = builtinFunc{"ceil", func(a ...any) (any, ArErr) {
vars.obj["ceil"] = builtinFunc{"ceil", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{TYPE: "ceil", message: "ceil takes 1 argument",
EXISTS: true}
@@ -138,36 +138,10 @@ func init() {
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot ceil '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["append"] = builtinFunc{"append", func(a ...any) (any, ArErr) {
if len(a) != 2 {
return nil, ArErr{TYPE: "append", message: "append takes 2 arguments, got " + fmt.Sprint(len(a)),
EXISTS: true}
}
switch x := a[0].(type) {
case ArArray:
return append(x, a[1]), ArErr{}
case string:
if typeof(a[1]) != "string" {
return nil, ArErr{TYPE: "TypeError", message: "Cannot append '" + typeof(a[1]) + "' to string", EXISTS: true}
}
return strings.Join([]string{x, a[1].(string)}, ""), ArErr{}
case ArMap:
if typeof(a[1]) != "array" {
return nil, ArErr{TYPE: "TypeError", message: "Cannot append '" + typeof(a[1]) + "' to map", EXISTS: true}
}
y := a[1].(ArArray)
if len(y) != 2 {
return nil, ArErr{TYPE: "TypeError", message: "Cannot append '" + typeof(a[1]) + "' to map", EXISTS: true}
}
x[y[0]] = y[1]
return x, ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot append to '" + typeof(a[0]) + "'", EXISTS: true}
}}
vars["sqrt"] = builtinFunc{"sqrt", ArgonSqrt}
vars["file"] = ArFile
vars["random"] = ArRandom
vars["json"] = ArJSON
vars["sin"] = ArSin
vars["arcsin"] = ArArcsin
vars.obj["sqrt"] = builtinFunc{"sqrt", ArgonSqrt}
vars.obj["file"] = ArFile
vars.obj["random"] = ArRandom
vars.obj["json"] = ArJSON
vars.obj["sin"] = ArSin
vars.obj["arcsin"] = ArArcsin
}

View File

@@ -15,6 +15,14 @@ type call struct {
path string
}
type Callable struct {
params []string
run any
code string
stack stack
line int
}
func isCall(code UNPARSEcode) bool {
return callCompile.MatchString(code.code)
}
@@ -30,7 +38,7 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool,
for i := 1; i < len(splitby); i++ {
name := strings.Join(splitby[0:i], "(")
argstr := strings.Join(splitby[i:], "(")
args, success, argserr := getValuesFromLetter(argstr, ",", index, codelines, true)
args, success, argserr := getValuesFromLetter(argstr, ",", index, codelines, false)
arguments = args
if !success {
if i == len(splitby)-1 {
@@ -68,13 +76,13 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
return nil, err
}
switch x := callable_.(type) {
case ArMap:
callable_ = x["__call__"]
case ArObject:
callable_ = x.obj["__call__"]
}
callable = callable_
}
args := []any{}
level := append(stack, scope{})
level := append(stack, newscope())
for _, arg := range c.args {
resp, err := runVal(arg, level, stacklevel+1)
if err.EXISTS {
@@ -101,9 +109,9 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
if len(x.params) != len(args) {
return nil, ArErr{"Runtime Error", "expected " + fmt.Sprint(len(x.params)) + " arguments, got " + fmt.Sprint(len(args)), c.line, c.path, c.code, true}
}
level := scope{}
level := newscope()
for i, param := range x.params {
level[param] = args[i]
level.obj[param] = args[i]
}
resp, err := runVal(x.run, append(x.stack, level), stacklevel+1)
return ThrowOnNonLoop(openReturn(resp), err)

View File

@@ -1,9 +0,0 @@
package main
type Callable struct {
params []string
run any
code string
stack stack
line int
}

View File

@@ -49,7 +49,7 @@ func parseDoWrap(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, boo
}
func runDoWrap(d dowrap, stack stack, stacklevel int) (any, ArErr) {
newstack := append(stack, scope{})
newstack := append(stack, newscope())
for _, v := range d.run {
val, err := runVal(v, newstack, stacklevel+1)
if err.EXISTS {

View File

@@ -7,10 +7,10 @@ import (
"os"
)
var ArFile = ArMap{
var ArFile = Map(anymap{
"read": builtinFunc{"read", ArRead},
"write": builtinFunc{"write", ArWrite},
}
})
func readtext(file *os.File) (string, error) {
var buf bytes.Buffer
@@ -23,68 +23,68 @@ func readtext(file *os.File) (string, error) {
func ArRead(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "read takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "read takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "string" {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "read takes a string not type '" + typeof(args[0]) + "'", EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "read takes a string not type '" + typeof(args[0]) + "'", EXISTS: true}
}
filename := args[0].(string)
file, err := os.Open(filename)
if err != nil {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return ArMap{
return Map(anymap{
"text": builtinFunc{"text", func(...any) (any, ArErr) {
text, err := readtext(file)
if err != nil {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return text, ArErr{}
}},
"json": builtinFunc{"json", func(...any) (any, ArErr) {
text, err := readtext(file)
if err != nil {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return jsonparse(text), ArErr{}
}},
}, ArErr{}
}), ArErr{}
}
func ArWrite(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "write takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "write takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "string" {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "write takes a string not type '" + typeof(args[0]) + "'", EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "write takes a string not type '" + typeof(args[0]) + "'", EXISTS: true}
}
filename := args[0].(string)
file, err := os.Create(filename)
if err != nil {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return ArMap{
return Map(anymap{
"text": builtinFunc{"text", func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "text takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "text takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "string" {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "text takes a string not type '" + typeof(args[0]) + "'", EXISTS: true}
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 ArMap{}, ArErr{TYPE: "Runtime Error", message: "json takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
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 ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
file.Write([]byte(jsonstr))
return nil, ArErr{}
}},
}, ArErr{}
}), ArErr{}
}

View File

@@ -5,15 +5,19 @@ import (
"strings"
)
type ArMap = map[any]any
type ArArray = []any
type ArObject struct {
TYPE string
obj anymap
}
type anymap map[any]any
var mapGetCompile = makeRegex(`(.|\n)+\.([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`)
var indexGetCompile = makeRegex(`(.|\n)+\[(.|\n)+\]( *)`)
type ArMapGet struct {
VAL any
args ArArray
args []any
index bool
line int
code string
@@ -26,7 +30,14 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
return nil, err
}
switch m := resp.(type) {
case ArMap:
case ArObject:
switch m.TYPE {
case "array":
resp, err := getFromArArray(m, r, stack, stacklevel+1)
if !err.EXISTS {
return resp, err
}
}
if len(r.args) > 1 {
return nil, ArErr{
"IndexError",
@@ -51,7 +62,7 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
true,
}
}
if _, ok := m[key]; !ok {
if _, ok := m.obj[key]; !ok {
return nil, ArErr{
"KeyError",
"key '" + fmt.Sprint(key) + "' not found",
@@ -61,12 +72,15 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
true,
}
}
return m[key], ArErr{}
case ArArray:
return getFromArArray(m, r, stack, stacklevel)
return potentialAnyArrayToArArray(m.obj[key]), ArErr{}
case string:
return getFromString(m, r, stack, stacklevel)
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)
}
key, err := runVal(r.args[0], stack, stacklevel+1)
@@ -84,9 +98,9 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
}
func classVal(r any) any {
if _, ok := r.(ArMap); ok {
if _, ok := r.(ArMap)["__value__"]; ok {
return r.(ArMap)["__value__"]
if j, ok := r.(ArObject); ok {
if _, ok := j.obj["__value__"]; ok {
return j.obj["__value__"]
}
}
return r
@@ -105,7 +119,7 @@ func mapGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapGet
if !worked {
return ArMapGet{}, false, err, i
}
return ArMapGet{resp, ArArray{key}, false, code.line, code.realcode, code.path}, true, ArErr{}, 1
return ArMapGet{resp, []any{key}, false, code.line, code.realcode, code.path}, true, ArErr{}, 1
}
func isIndexGet(code UNPARSEcode) bool {
@@ -126,7 +140,6 @@ func indexGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapG
}
continue
}
fmt.Println(args)
if len(args) > 3 {
return ArMapGet{}, false, ArErr{
"SyntaxError",
@@ -161,7 +174,7 @@ func isUnhashable(val any) bool {
return keytype == "array" || keytype == "map"
}
func getFromArArray(m []any, r ArMapGet, stack stack, stacklevel int) (ArArray, ArErr) {
func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (ArObject, ArErr) {
var (
start int = 0
end any = nil
@@ -170,12 +183,12 @@ func getFromArArray(m []any, r ArMapGet, stack stack, stacklevel int) (ArArray,
{
startval, err := runVal(r.args[0], stack, stacklevel+1)
if err.EXISTS {
return nil, err
return ArObject{}, err
}
if startval == nil {
start = 0
} else if typeof(startval) != "number" && !startval.(number).IsInt() {
return nil, ArErr{
} else if typeof(startval) != "number" || !startval.(number).IsInt() {
return ArObject{}, ArErr{
"TypeError",
"slice index must be an integer",
r.line,
@@ -190,12 +203,12 @@ func getFromArArray(m []any, r ArMapGet, stack stack, stacklevel int) (ArArray,
if len(r.args) > 1 {
endval, err := runVal(r.args[1], stack, stacklevel+1)
if err.EXISTS {
return nil, err
return ArObject{}, err
}
if endval == nil {
end = len(m)
end = m.obj["length"]
} else if typeof(endval) != "number" && !endval.(number).IsInt() {
return nil, ArErr{
return ArObject{}, ArErr{
"TypeError",
"slice ending index must be an integer",
r.line,
@@ -210,12 +223,12 @@ func getFromArArray(m []any, r ArMapGet, stack stack, stacklevel int) (ArArray,
if len(r.args) > 2 {
stepval, err := runVal(r.args[2], stack, stacklevel+1)
if err.EXISTS {
return nil, err
return ArObject{}, err
}
if stepval == nil {
step = 1
} else if typeof(stepval) != "number" && !stepval.(number).IsInt() {
return nil, ArErr{
return ArObject{}, ArErr{
"TypeError",
"slice step must be an integer",
r.line,
@@ -228,29 +241,27 @@ func getFromArArray(m []any, r ArMapGet, stack stack, stacklevel int) (ArArray,
}
}
if start < 0 {
start = len(m) + start
start = m.obj["length"].(int) + start
}
if _, ok := end.(int); ok && end.(int) < 0 {
end = len(m) + end.(int)
end = m.obj["length"].(int) + end.(int)
}
fmt.Println(start, end, step)
if end == nil {
return ArArray{m[start]}, ArErr{}
return ArArray([]any{m.obj["__value__"].([]any)[start]}), ArErr{}
} else if step == 1 {
return m[start:end.(int)], ArErr{}
return ArArray([]any{m.obj["__value__"].([]any)[start:end.(int)]}), ArErr{}
} else {
output := ArArray{}
output := []any{}
if step > 0 {
for i := start; i < end.(int); i += step {
output = append(output, m[i])
output = append(output, m.obj["__value__"].([]any)[i])
}
} else {
for i := end.(int) - 1; i >= start; i += step {
output = append(output, m[i])
output = append(output, m.obj["__value__"].([]any)[i])
}
}
return (output), ArErr{}
return ArArray(output), ArErr{}
}
}
@@ -267,7 +278,7 @@ func getFromString(m string, r ArMapGet, stack stack, stacklevel int) (string, A
}
if startval == nil {
start = 0
} else if typeof(startval) != "number" && !startval.(number).IsInt() {
} else if typeof(startval) != "number" || !startval.(number).IsInt() {
return "", ArErr{
"TypeError",
"slice index must be an integer",
@@ -326,8 +337,6 @@ func getFromString(m string, r ArMapGet, stack stack, stacklevel int) (string, A
if _, ok := end.(int); ok && end.(int) < 0 {
end = len(m) + end.(int)
}
fmt.Println(start, end, step)
if end == nil {
return string(m[start]), ArErr{}
} else if step == 1 {

View File

@@ -118,7 +118,7 @@ func parseIfStatement(code UNPARSEcode, index int, codeline []UNPARSEcode) (ifst
func runIfStatement(code ifstatement, stack stack, stacklevel int) (any, ArErr) {
for _, condition := range code.conditions {
newstack := append(stack, scope{})
newstack := append(stack, newscope())
resp, err := runVal(condition.condition, newstack, stacklevel+1)
if err.EXISTS {
return nil, err
@@ -128,7 +128,7 @@ func runIfStatement(code ifstatement, stack stack, stacklevel int) (any, ArErr)
}
}
if code.ELSE != nil {
return runVal(code.ELSE, append(stack, scope{}), stacklevel+1)
return runVal(code.ELSE, append(stack, newscope()), stacklevel+1)
}
return nil, ArErr{}
}

View File

@@ -8,6 +8,9 @@ import (
"path/filepath"
)
var imported = make(map[string]ArObject)
var importing = make(map[string]bool)
func FileExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
@@ -44,7 +47,7 @@ func readFile(path string) []UNPARSEcode {
return output
}
func importMod(realpath string, origin string) (scope, ArErr) {
func importMod(realpath string, origin string, main bool) (ArObject, ArErr) {
extention := filepath.Ext(realpath)
path := realpath
if extention == "" {
@@ -52,13 +55,13 @@ func importMod(realpath string, origin string) (scope, ArErr) {
}
ex, err := os.Getwd()
if err != nil {
return nil, ArErr{"Import Error", err.Error(), 0, realpath, "", true}
return ArObject{}, ArErr{TYPE: "Import Error", message: "Could not get working directory", EXISTS: true}
}
executable, err := os.Executable()
exc, err := os.Executable()
if err != nil {
return nil, ArErr{"Import Error", err.Error(), 0, realpath, "", true}
return ArObject{}, ArErr{TYPE: "Import Error", message: "Could not get executable", EXISTS: true}
}
executable = filepath.Dir(executable)
executable := filepath.Dir(exc)
isABS := filepath.IsAbs(path)
var pathsToTest []string
if isABS {
@@ -90,18 +93,52 @@ func importMod(realpath string, origin string) (scope, ArErr) {
}
if !found {
return nil, ArErr{"Import Error", "File does not exist: " + realpath, 0, realpath, "", true}
return ArObject{}, ArErr{TYPE: "Import Error", message: "File does not exist: " + realpath, EXISTS: true}
} else if importing[p] {
return ArObject{}, ArErr{TYPE: "Import Error", message: "Circular import: " + realpath, EXISTS: true}
} else if _, ok := imported[p]; ok {
return imported[p], ArErr{}
}
importing[p] = true
codelines := readFile(p)
translated, translationerr := translate(codelines)
if translationerr.EXISTS {
return nil, translationerr
return ArObject{}, translationerr
}
global := scope{}
_, runimeErr, _ := run(translated, stack{vars, global})
ArgsArArray := []any{}
for _, arg := range Args[1:] {
ArgsArArray = append(ArgsArArray, arg)
}
global := newscope()
localvars := Map(anymap{
"program": Map(anymap{
"args": ArArray(ArgsArArray),
"origin": origin,
"import": builtinFunc{"import", func(args ...any) (any, ArErr) {
if len(args) != 1 {
return nil, ArErr{"Import Error", "Invalid number of arguments", 0, realpath, "", true}
}
if _, ok := args[0].(string); !ok {
return nil, ArErr{"Import Error", "Invalid argument type", 0, realpath, "", true}
}
return importMod(args[0].(string), filepath.Dir(p), false)
}},
"cwd": ex,
"exc": exc,
"file": Map(anymap{
"name": filepath.Base(p),
"path": p,
}),
"main": main,
"scope": global,
}),
})
_, runimeErr, _ := run(translated, stack{vars, localvars, global})
importing[p] = false
if runimeErr.EXISTS {
return nil, runimeErr
return ArObject{}, runimeErr
}
imported[p] = global
return global, ArErr{}
}

View File

@@ -11,17 +11,13 @@ import (
func convertToArgon(obj any) any {
switch x := obj.(type) {
case map[string]interface{}:
newmap := ArMap{}
newmap := Map(anymap{})
for key, value := range x {
newmap[key] = convertToArgon(value)
newmap.obj[key] = convertToArgon(value)
}
return newmap
case ArArray:
newarray := ArArray{}
for _, value := range x {
newarray = append(newarray, convertToArgon(value))
}
return newarray
case []any:
return ArArray(x)
case string:
return x
case float64:
@@ -47,8 +43,18 @@ func jsonstringify(obj any, level int) (string, error) {
output := []string{}
obj = classVal(obj)
switch x := obj.(type) {
case ArMap:
for key, value := range x {
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 {
return "", err
@@ -56,7 +62,7 @@ func jsonstringify(obj any, level int) (string, error) {
output = append(output, ""+strconv.Quote(anyToArgon(key, false, true, 3, 0, false, 0))+": "+str)
}
return "{" + strings.Join(output, ", ") + "}", nil
case ArArray:
case []any:
for _, value := range x {
str, err := jsonstringify(value, level+1)
if err != nil {
@@ -82,24 +88,24 @@ func jsonstringify(obj any, level int) (string, error) {
return "", err
}
var ArJSON = ArMap{
var ArJSON = Map(anymap{
"parse": builtinFunc{"parse", func(args ...any) (any, ArErr) {
if len(args) == 0 {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "parse takes 1 argument", EXISTS: true}
return nil, ArErr{TYPE: "Runtime Error", message: "parse takes 1 argument", EXISTS: true}
}
if typeof(args[0]) != "string" {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "parse takes a string not a '" + typeof(args[0]) + "'", EXISTS: true}
return nil, ArErr{TYPE: "Runtime Error", message: "parse takes a string not a '" + typeof(args[0]) + "'", EXISTS: true}
}
return jsonparse(args[0].(string)), ArErr{}
}},
"stringify": builtinFunc{"stringify", func(args ...any) (any, ArErr) {
if len(args) == 0 {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: "stringify takes 1 argument", EXISTS: true}
return nil, ArErr{TYPE: "Runtime Error", message: "stringify takes 1 argument", EXISTS: true}
}
str, err := jsonstringify(args[0], 0)
if err != nil {
return ArMap{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
return nil, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return str, ArErr{}
}},
}
})

View File

@@ -7,8 +7,14 @@ import (
// args without the program path
var Args = os.Args[1:]
type scope = ArMap
type stack = []scope
type stack = []ArObject
func newscope() ArObject {
return ArObject{
TYPE: "map",
obj: make(anymap),
}
}
func main() {
ex, e := os.Getwd()
@@ -19,7 +25,7 @@ func main() {
shell()
os.Exit(0)
}
_, err := importMod(Args[0], ex)
_, err := importMod(Args[0], ex, true)
if err.EXISTS {
panicErr(err)
os.Exit(1)

8
src/map.go Normal file
View File

@@ -0,0 +1,8 @@
package main
func Map(val anymap) ArObject {
return ArObject{
TYPE: "map",
obj: val,
}
}

View File

@@ -56,21 +56,30 @@ func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
if e != nil {
return nil, ArErr{"File Error", "could not get current working directory", importOBJ.line, importOBJ.path, importOBJ.code, true}
}
stackMap, err := importMod(path, ex)
stackMap, err := importMod(path, ex, false)
if err.EXISTS {
if err.line == 0 {
err.line = importOBJ.line
}
if err.path == "" {
err.path = importOBJ.path
}
if err.code == "" {
err.code = importOBJ.code
}
return nil, err
}
switch x := importOBJ.values.(type) {
case []string:
for _, v := range x {
val, ok := stackMap[v]
val, ok := stackMap.obj[v]
if !ok {
return nil, ArErr{"Import Error", "could not find value " + anyToArgon(v, true, false, 3, 0, false, 0) + " in module " + anyToArgon(path, true, false, 3, 0, false, 0), importOBJ.line, importOBJ.path, importOBJ.code, true}
}
stack[len(stack)-1][v] = val
stack[len(stack)-1].obj[v] = val
}
case string:
stack[len(stack)-1][x] = stackMap
stack[len(stack)-1].obj[x] = stackMap
}
return nil, ArErr{}
}

View File

@@ -49,7 +49,7 @@ func randomRange(args ...any) (any, ArErr) {
return rand, ArErr{}
}
var ArRandom = ArMap{
var ArRandom = Map(anymap{
"__call__": builtinFunc{"random", func(args ...any) (any, ArErr) {
if len(args) != 0 {
return nil, ArErr{
@@ -68,7 +68,7 @@ var ArRandom = ArMap{
return round(resp.(number), 0), ArErr{}
}},
"range": builtinFunc{"range", randomRange},
}
})
func init() {
rand.Seed(

View File

@@ -7,7 +7,7 @@ import (
)
func shell() {
global := stack{vars, scope{}}
global := stack{vars, newscope()}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {

View File

@@ -5,9 +5,9 @@ import (
"time"
)
var timing = ArMap{}
var timing = anymap{}
var plain = ArMap{
var plain = Map(anymap{
"log": builtinFunc{"log", func(args ...any) (any, ArErr) {
output := []any{}
for i := 0; i < len(args); i++ {
@@ -32,9 +32,9 @@ var plain = ArMap{
fmt.Println(output...)
return nil, ArErr{}
}},
}
})
var ArTerm = ArMap{
var ArTerm = Map(anymap{
"log": builtinFunc{"log", func(args ...any) (any, ArErr) {
output := []any{}
for i := 0; i < len(args); i++ {
@@ -103,4 +103,4 @@ var ArTerm = ArMap{
fmt.Printf("\x1b[%dm%s\x1b[0m", 34, fmt.Sprint(anyToArgon(id, false, true, 3, 0, false, 0), ": ", timesince)+"\n")
return nil, ArErr{}
}},
}
})

View File

@@ -17,11 +17,11 @@ func ArThread(args ...any) (any, ArErr) {
}
var resp any
var err ArErr
currentscope := stack{vars, scope{}}
currentscope := stack{vars, newscope()}
hasrun := false
joined := false
var wg sync.WaitGroup
threaMap := ArMap{
threadMap := Map(anymap{
"start": builtinFunc{"start", func(args ...any) (any, ArErr) {
if hasrun {
return nil, ArErr{TYPE: "Runtime Error", message: "Cannot start a thread twice", EXISTS: true}
@@ -44,6 +44,6 @@ func ArThread(args ...any) (any, ArErr) {
wg.Wait()
return resp, err
}},
}
return threaMap, ArErr{}
})
return threadMap, ArErr{}
}

View File

@@ -6,8 +6,8 @@ import (
var MicroSeconds = newNumber().SetInt64(1000000)
func ArTimeClass(N time.Time) ArMap {
return ArMap{
func ArTimeClass(N time.Time) ArObject {
return Map(anymap{
"__value__": newNumber().Quo(newNumber().SetInt64(N.UnixMicro()), MicroSeconds),
"year": builtinFunc{
"year",
@@ -96,10 +96,10 @@ func ArTimeClass(N time.Time) ArMap {
return N.Format(a[0].(string)), ArErr{}
},
},
}
})
}
var ArTime = map[any]any{
var ArTime = Map(anymap{
"snooze": builtinFunc{"snooze", func(a ...any) (any, ArErr) {
if len(a) > 0 {
float, _ := a[0].(number).Float64()
@@ -212,4 +212,4 @@ var ArTime = map[any]any{
}
},
},
}
})

View File

@@ -72,17 +72,17 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
if colored {
output = append(output, "\x1b[0m")
}
case ArMap:
if _, ok := x["__value__"]; ok {
return anyToArgon(x["__value__"], quote, simplify, depth, indent, colored, plain)
case ArObject:
if x.TYPE == "array" {
return anyToArgon(x.obj["__value__"], quote, simplify, depth, indent, colored, plain)
}
if len(x) == 0 {
if len(x.obj) == 0 {
return "{}"
}
keys := make([]any, len(x))
keys := make([]any, len(x.obj))
i := 0
for k := range x {
for k := range x.obj {
keys[i] = k
i++
}
@@ -103,13 +103,11 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
}
keyval = strings.Join(outputkeyval, "")
}
output = append(output, keyval+": "+anyToArgon(x[key], true, true, depth-1, indent+1, colored, plain))
output = append(output, keyval+": "+anyToArgon(x.obj[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 ArArray:
if len(x) == 0 {
return "[]"
}
case []any:
singleline := len(x) <= 3
output := []string{}
if simplify && len(x) >= 100 {
for i := 0; i < 10; i++ {
@@ -128,9 +126,17 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
} else {
for i := 0; i < len(x); i++ {
item := x[i]
output = append(output, anyToArgon(item, true, true, depth-1, indent+1, colored, plain))
converted := anyToArgon(item, true, true, depth-1, indent+1, colored, plain)
if singleline && strings.Contains(converted, "\n") {
singleline = false
}
output = append(output, converted)
}
}
if singleline {
return "[" + strings.Join(output, ", ") + "]"
}
return "[" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "]"
case builtinFunc:
if colored {

View File

@@ -1,7 +1,7 @@
package main
func typeof(val any) string {
switch val.(type) {
switch x := val.(type) {
case number:
return "number"
case string:
@@ -14,10 +14,11 @@ func typeof(val any) string {
return "function"
case builtinFunc:
return "function"
case ArMap:
case ArObject:
if x.TYPE == "array" {
return "array"
}
return "map"
case ArArray:
return "array"
case accessVariable:
return "variable"
}

View File

@@ -78,7 +78,7 @@ func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) {
func readVariable(v accessVariable, stack stack) (any, ArErr) {
for i := len(stack) - 1; i >= 0; i-- {
varMutex.RLock()
val, ok := stack[i][v.name]
val, ok := stack[i].obj[v.name]
varMutex.RUnlock()
if ok {
return val, ArErr{}
@@ -208,30 +208,30 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
if v.TYPE == "let" {
varMutex.RLock()
_, ok := stack[len(stack)-1][v.toset.(accessVariable).name]
_, ok := stack[len(stack)-1].obj[v.toset.(accessVariable).name]
varMutex.RUnlock()
if ok {
return nil, ArErr{"Runtime Error", "variable \"" + v.toset.(accessVariable).name + "\" already exists", v.line, v.path, v.code, true}
}
varMutex.Lock()
stack[len(stack)-1][v.toset.(accessVariable).name] = resp
stack[len(stack)-1].obj[v.toset.(accessVariable).name] = resp
varMutex.Unlock()
} else {
switch x := v.toset.(type) {
case accessVariable:
for i := len(stack) - 1; i >= 0; i-- {
varMutex.RLock()
_, ok := stack[i][x.name]
_, ok := stack[i].obj[x.name]
varMutex.RUnlock()
if ok {
varMutex.Lock()
stack[i][x.name] = resp
stack[i].obj[x.name] = resp
varMutex.Unlock()
return ThrowOnNonLoop(resp, ArErr{})
}
}
varMutex.Lock()
stack[len(stack)-1][x.name] = resp
stack[len(stack)-1].obj[x.name] = resp
varMutex.Unlock()
case ArMapGet:
respp, err := runVal(x.VAL, stack, stacklevel+1)
@@ -246,12 +246,12 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
return nil, err
}
switch y := respp.(type) {
case ArMap:
case ArObject:
if isUnhashable(key) {
return nil, ArErr{"Runtime Error", "can't use unhashable type as map key: " + typeof(key), v.line, v.path, v.code, true}
}
varMutex.Lock()
y[key] = resp
y.obj[key] = resp
varMutex.Unlock()
default:
return nil, ArErr{"Runtime Error", "can't set for non map", v.line, v.path, v.code, true}
@@ -285,8 +285,8 @@ func runDelete(d ArDelete, stack stack, stacklevel int) (any, ArErr) {
switch x := d.value.(type) {
case accessVariable:
for i := len(stack) - 1; i >= 0; i-- {
if _, ok := stack[i][x.name]; ok {
delete(stack[i], x.name)
if _, ok := stack[i].obj[x.name]; ok {
delete(stack[i].obj, x.name)
return nil, ArErr{}
}
}
@@ -304,8 +304,14 @@ func runDelete(d ArDelete, stack stack, stacklevel int) (any, ArErr) {
return nil, err
}
switch y := respp.(type) {
case ArMap:
delete(y, key)
case ArObject:
if y.TYPE == "array" {
return nil, ArErr{"Runtime Error", "can't delete from array", d.line, d.path, d.code, true}
}
if isUnhashable(key) {
return nil, ArErr{"Runtime Error", "can't use unhashable type as map key: " + typeof(key), d.line, d.path, d.code, true}
}
delete(y.obj, key)
default:
return nil, ArErr{"Runtime Error", "can't delete for non map", d.line, d.path, d.code, true}
}