make strings objects

This commit is contained in:
2023-03-19 20:05:43 +00:00
parent 2e04bb0152
commit a080152aee
9 changed files with 559 additions and 181 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"fmt"
"strings"
)
@@ -25,6 +26,122 @@ func ArArray(arr []any) ArObject {
"length": newNumber().SetUint64(uint64(len(arr))),
},
}
val.obj["__setindex__"] = builtinFunc{
"__setindex__",
func(a ...any) (any, ArErr) {
if len(a) != 2 {
return nil, ArErr{
TYPE: "TypeError",
message: "expected 2 arguments, got " + fmt.Sprint(len(a)),
EXISTS: true,
}
}
if typeof(a[0]) != "number" {
return nil, ArErr{
TYPE: "TypeError",
message: "index must be a number",
EXISTS: true,
}
}
if !a[0].(number).IsInt() {
return nil, ArErr{
TYPE: "TypeError",
message: "index must be an integer",
EXISTS: true,
}
}
num := int(a[0].(number).Num().Int64())
if num < 0 || num >= len(arr) {
return nil, ArErr{
TYPE: "IndexError",
message: "index out of range",
EXISTS: true,
}
}
arr[num] = a[1]
return nil, ArErr{}
},
}
val.obj["__getindex__"] = builtinFunc{
"__getindex__",
func(a ...any) (any, ArErr) {
// a[0] is start
// a[1] is end
// a[2] is step
if len(a) < 0 || len(a) > 3 {
return nil, ArErr{"TypeError", "expected 1 to 3 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
var (
start int = 0
end any = nil
step int = 1
)
{
if a[0] == nil {
start = 0
} else if typeof(a[0]) != "number" || !a[0].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
start = int(a[0].(number).Num().Int64())
}
}
if len(a) > 1 {
if a[1] == nil {
end = len(arr)
} else if typeof(a[1]) != "number" || !a[1].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
end = int(a[1].(number).Num().Int64())
}
}
if len(a) > 2 {
if a[2] == nil {
step = 1
} else if typeof(a[2]) != "number" || !a[2].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
step = int(a[2].(number).Num().Int64())
}
}
if start < 0 {
start = len(arr) + start
}
if _, ok := end.(int); ok && end.(int) < 0 {
end = len(arr) + end.(int)
}
if end != nil && end.(int) > len(arr) {
end = len(arr)
}
if end == nil {
return arr[start], ArErr{}
} else if step == 1 {
return arr[start:end.(int)], ArErr{}
} else {
output := []any{}
if step > 0 {
for i := start; i < end.(int); i += step {
output = append(output, arr[i])
}
} else {
for i := end.(int) - 1; i >= start; i += step {
output = append(output, arr[i])
}
}
return output, ArErr{}
}
}}
val.obj["remove"] = builtinFunc{
"remove",
func(args ...any) (any, ArErr) {

View File

@@ -1,5 +1,7 @@
package main
import "fmt"
var vars = Map(anymap{})
func init() {
@@ -133,4 +135,20 @@ func init() {
vars.obj["json"] = ArJSON
vars.obj["sin"] = ArSin
vars.obj["arcsin"] = ArArcsin
vars.obj["dir"] = builtinFunc{"dir", func(a ...any) (any, ArErr) {
fmt.Println(a)
if len(a) == 0 {
return ArArray([]any{}), ArErr{}
}
t := AnyToArValid(a[0])
switch x := t.(type) {
case ArObject:
newarray := []any{}
for key := range x.obj {
newarray = append(newarray, key)
}
return ArArray(newarray), ArErr{}
}
return ArArray([]any{}), ArErr{}
}}
}

View File

@@ -97,71 +97,3 @@ func readtext(file *os.File) (string, error) {
}
return buf.String(), nil
}
func ArRead(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "read takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "string" {
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 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{}
}
func ArWrite(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "write takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "string" {
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 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{}
}},
}), ArErr{}
}

View File

@@ -31,16 +31,19 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
}
switch m := resp.(type) {
case ArObject:
switch m.TYPE {
case "array":
resp, err := getFromArArray(m, r, stack, stacklevel+1)
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 r.index && m.TYPE != "map" {
if _, ok := m.obj["__getindex__"]; ok {
callable := m.obj["__getindex__"]
resp, err := runCall(call{
callable: callable,
args: r.args,
line: r.line,
path: r.path,
code: r.code,
}, stack, stacklevel+1)
if !err.EXISTS {
return resp, ArErr{}
}
}
}
if len(r.args) > 1 {
@@ -253,94 +256,3 @@ func getFromArArray(m ArObject, r ArMapGet, stack stack, stacklevel int) (any, A
return ArArray(output), ArErr{}
}
}
func getFromString(m string, r ArMapGet, stack stack, stacklevel int) (string, ArErr) {
var (
start int = 0
end any = nil
step int = 1
)
{
startval, err := runVal(r.args[0], stack, stacklevel+1)
if err.EXISTS {
return "", err
}
if startval == nil {
start = 0
} else if typeof(startval) != "number" || !startval.(number).IsInt() {
return "", 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 "", err
}
if endval == nil {
end = len(m)
} else if typeof(endval) != "number" && !endval.(number).IsInt() {
return "", 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 "", err
}
if stepval == nil {
step = 1
} else if typeof(stepval) != "number" && !stepval.(number).IsInt() {
return "", 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 = len(m) + start
}
if _, ok := end.(int); ok && end.(int) < 0 {
end = len(m) + end.(int)
}
if end == nil {
return string(m[start]), ArErr{}
} else if step == 1 {
return m[start:end.(int)], ArErr{}
} else {
output := []byte{}
if step > 0 {
for i := start; i < end.(int); i += step {
output = append(output, m[i])
}
} else {
for i := end.(int) - 1; i >= start; i += step {
output = append(output, m[i])
}
}
return string(output), ArErr{}
}
}

View File

@@ -45,6 +45,7 @@ func parseGenericImport(code UNPARSEcode, index int, codeline []UNPARSEcode) (Ar
func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
val, err := runVal(importOBJ.filePath, stack, stacklevel+1)
val = ArValidToAny(val)
if err.EXISTS {
return nil, err
}

View File

@@ -1,6 +1,7 @@
package main
import (
"fmt"
"strconv"
"strings"
)
@@ -50,6 +51,118 @@ func ArString(str string) ArObject {
"length": newNumber().SetUint64(uint64(len(str))),
},
}
obj.obj["__setindex__"] = builtinFunc{
"__setindex__",
func(a ...any) (any, ArErr) {
if len(a) != 2 {
return nil, ArErr{"TypeError", "expected 2 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "number" {
return nil, ArErr{"TypeError", "expected number, got " + typeof(a[0]), 0, "", "", true}
}
if typeof(a[1]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[1]), 0, "", "", true}
}
if len(a[1].(string)) != 1 {
return nil, ArErr{"TypeError", "expected string of length 1, got " + fmt.Sprint(len(a[1].(string))), 0, "", "", true}
}
if !a[0].(number).IsInt() {
return nil, ArErr{"TypeError", "expected integer, got float", 0, "", "", true}
}
index := a[0].(number).Num().Int64()
if index < 0 {
index = int64(len(str)) + index
}
if index < 0 || index >= int64(len(str)) {
return nil, ArErr{"IndexError", "index out of range", 0, "", "", true}
}
str = strings.Join([]string{str[:index], a[1].(string), str[index+1:]}, "")
obj.obj["__value__"] = str
obj.obj["length"] = newNumber().SetUint64(uint64(len(str)))
return nil, ArErr{}
}}
obj.obj["__getindex__"] = builtinFunc{
"__getindex__",
func(a ...any) (any, ArErr) {
// a[0] is start
// a[1] is end
// a[2] is step
if len(a) < 0 || len(a) > 3 {
return nil, ArErr{"TypeError", "expected 1 to 3 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
var (
start int = 0
end any = nil
step int = 1
)
{
if a[0] == nil {
start = 0
} else if typeof(a[0]) != "number" || !a[0].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
start = int(a[0].(number).Num().Int64())
}
}
if len(a) > 1 {
if a[1] == nil {
end = len(str)
} else if typeof(a[1]) != "number" || !a[1].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
end = int(a[1].(number).Num().Int64())
}
}
if len(a) > 2 {
if a[2] == nil {
step = 1
} else if typeof(a[2]) != "number" || !a[2].(number).IsInt() {
return "", ArErr{
TYPE: "TypeError",
message: "slice index must be an integer",
EXISTS: true,
}
} else {
step = int(a[2].(number).Num().Int64())
}
}
if start < 0 {
start = len(str) + start
}
if _, ok := end.(int); ok && end.(int) < 0 {
end = len(str) + end.(int)
}
if end != nil && end.(int) > len(str) {
end = len(str)
}
if end == nil {
return string(str[start]), ArErr{}
} else if step == 1 {
return str[start:end.(int)], ArErr{}
} else {
output := []byte{}
if step > 0 {
for i := start; i < end.(int); i += step {
output = append(output, str[i])
}
} else {
for i := end.(int) - 1; i >= start; i += step {
output = append(output, str[i])
}
}
return string(output), ArErr{}
}
}}
obj.obj["append"] = builtinFunc{
"append",
func(a ...any) (any, ArErr) {
@@ -68,5 +181,230 @@ func ArString(str string) ArObject {
obj.obj["length"] = newNumber().SetUint64(uint64(len(str)))
return nil, ArErr{}
}}
obj.obj["extend"] = builtinFunc{
"extend",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 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{}
},
}
obj.obj["insert"] = builtinFunc{
"insert",
func(a ...any) (any, ArErr) {
if len(a) != 2 {
return nil, ArErr{"TypeError", "expected 2 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "number" || !a[0].(number).IsInt() {
return nil, ArErr{"TypeError", "expected integer, got " + typeof(a[0]), 0, "", "", true}
}
if typeof(a[1]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[1]), 0, "", "", true}
}
index := int(a[0].(number).Num().Int64())
if index < 0 {
index = len(str) + index
}
if index > len(str) {
index = len(str)
}
str = str[:index] + a[1].(string) + str[index:]
obj.obj["__value__"] = str
obj.obj["length"] = newNumber().SetUint64(uint64(len(str)))
return nil, ArErr{}
}}
obj.obj["concat"] = builtinFunc{
"concat",
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))
}
return strings.Join(output, ""), ArErr{}
}}
obj.obj["split"] = builtinFunc{
"split",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 or more argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
splitby := a[0].(string)
output := []any{}
splitted := any(strings.Split(str, splitby))
for _, v := range splitted.([]string) {
output = append(output, ArString(v))
}
return output, ArErr{}
}}
obj.obj["capitalise"] = builtinFunc{
"capitalise",
func(a ...any) (any, ArErr) {
if len(a) != 0 {
return nil, ArErr{"TypeError", "expected 0 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
return strings.Title(str), ArErr{}
}}
obj.obj["lower"] = builtinFunc{
"lower",
func(a ...any) (any, ArErr) {
if len(a) != 0 {
return nil, ArErr{"TypeError", "expected 0 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
return strings.ToLower(str), ArErr{}
}}
obj.obj["upper"] = builtinFunc{
"upper",
func(a ...any) (any, ArErr) {
if len(a) != 0 {
return nil, ArErr{"TypeError", "expected 0 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
return strings.ToUpper(str), ArErr{}
}}
obj.obj["replace"] = builtinFunc{
"replace",
func(a ...any) (any, ArErr) {
if len(a) != 2 {
return nil, ArErr{"TypeError", "expected 2 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
if typeof(a[1]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[1]), 0, "", "", true}
}
return strings.Replace(str, a[0].(string), a[1].(string), -1), ArErr{}
}}
obj.obj["contains"] = builtinFunc{
"contains",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.Contains(str, a[0].(string)), ArErr{}
}}
obj.obj["startswith"] = builtinFunc{
"startswith",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.HasPrefix(str, a[0].(string)), ArErr{}
}}
obj.obj["endswith"] = builtinFunc{
"endswith",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.HasSuffix(str, a[0].(string)), ArErr{}
}}
obj.obj["index"] = builtinFunc{
"index",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.Index(str, a[0].(string)), ArErr{}
}}
obj.obj["rindex"] = builtinFunc{
"rindex",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.LastIndex(str, a[0].(string)), ArErr{}
}}
obj.obj["count"] = builtinFunc{
"count",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
return strings.Count(str, a[0].(string)), ArErr{}
}}
obj.obj["strip"] = builtinFunc{
"strip",
func(a ...any) (any, ArErr) {
if len(a) > 1 {
return nil, ArErr{"TypeError", "expected 0 or 1 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
cutset := " "
if len(a) == 1 {
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
cutset = a[0].(string)
}
return strings.Trim(str, cutset), ArErr{}
}}
obj.obj["leftstrip"] = builtinFunc{
"leftstrip",
func(a ...any) (any, ArErr) {
if len(a) > 1 {
return nil, ArErr{"TypeError", "expected 0 or 1 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
cutset := " "
if len(a) == 1 {
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
cutset = a[0].(string)
}
return strings.TrimLeft(str, cutset), ArErr{}
}}
obj.obj["rightstrip"] = builtinFunc{
"rightstrip",
func(a ...any) (any, ArErr) {
if len(a) > 1 {
return nil, ArErr{"TypeError", "expected 0 or 1 arguments, got " + fmt.Sprint(len(a)), 0, "", "", true}
}
cutset := " "
if len(a) == 1 {
if typeof(a[0]) != "string" {
return nil, ArErr{"TypeError", "expected string, got " + typeof(a[0]), 0, "", "", true}
}
cutset = a[0].(string)
}
return strings.TrimRight(str, cutset), ArErr{}
}}
return obj
}

View File

@@ -249,12 +249,27 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
}
switch y := respp.(type) {
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}
if y.TYPE != "map" {
if _, ok := y.obj["__setindex__"]; ok {
callable := y.obj["__setindex__"]
r := ArValidToAny(resp)
_, err := runCall(call{
callable: callable,
args: []any{key, r},
line: v.line,
path: v.path,
code: v.code,
}, stack, stacklevel+1)
return nil, err
}
} else {
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.obj[key] = resp
varMutex.Unlock()
}
varMutex.Lock()
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}
}