From 364afa630d806f84f3dba703fcc879b23f90c0db Mon Sep 17 00:00:00 2001 From: William Bell Date: Sun, 26 Mar 2023 21:42:44 +0100 Subject: [PATCH] abs and modify operations so they are opp --- go.mod | 2 +- src/abs.go | 77 ++++++ src/array.go | 30 +++ src/built-in-functions.go | 3 + src/built-ins.go | 1 + src/map.go | 7 + src/operations.go | 518 +++++++++++++++++++++++++++----------- src/run.go | 16 +- src/sortany.go | 39 ++- src/string.go | 136 +++++++++- src/translate.go | 12 +- 11 files changed, 656 insertions(+), 185 deletions(-) create mode 100644 src/abs.go diff --git a/go.mod b/go.mod index a1d4992..0b51228 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module wbell.dev/m/v2 +module argon.wbell.dev go 1.19 diff --git a/src/abs.go b/src/abs.go new file mode 100644 index 0000000..5b87f6b --- /dev/null +++ b/src/abs.go @@ -0,0 +1,77 @@ +package main + +import ( + "fmt" + "strings" +) + +var AbsCompiled = makeRegex(`( *)\|(.|\n)+\|( *)`) + +type ABS struct { + body any + code string + line int + path string +} + +func isAbs(code UNPARSEcode) bool { + return AbsCompiled.MatchString(code.code) +} + +func parseAbs(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { + trimmed := strings.TrimSpace(code.code) + trimmed = trimmed[1 : len(trimmed)-1] + + val, worked, err, i := translateVal(UNPARSEcode{ + trimmed, + code.realcode, + code.line, + code.path, + }, index, codelines, 0) + if !worked { + return nil, false, err, 0 + } + return ABS{ + val, + code.realcode, + code.line, + code.path, + }, true, ArErr{}, i +} + +func runAbs(x ABS, stack stack, stacklevel int) (any, ArErr) { + resp, err := runVal(x.body, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + if typeof(resp) != "number" { + return nil, ArErr{TYPE: "Runtime Error", + message: fmt.Sprintf("abs expected number, got %s", typeof(resp)), + EXISTS: true, + } + } + return abs(resp.(number)), ArErr{} +} + +func abs(x number) number { + if x.Sign() < 0 { + return x.Neg(x) + } + return x +} + +var ArAbs = builtinFunc{"abs", func(args ...any) (any, ArErr) { + if len(args) != 1 { + return nil, ArErr{TYPE: "Runtime Error", + message: fmt.Sprintf("abs expected 1 argument, got %d", len(args)), + EXISTS: true, + } + } + if typeof(args[0]) != "number" { + return nil, ArErr{TYPE: "Runtime Error", + message: fmt.Sprintf("abs expected number, got %s", typeof(args[0])), + EXISTS: true, + } + } + return abs(args[0].(number)), ArErr{} +}} diff --git a/src/array.go b/src/array.go index dd68af2..fed25d4 100644 --- a/src/array.go +++ b/src/array.go @@ -533,6 +533,36 @@ func ArArray(arr []any) ArObject { return ArArray(newarr), ArErr{} }, } + val.obj["__Equal__"] = builtinFunc{ + "__LessThanEqual__", + 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 false, ArErr{} + } + if len(arr) != len(args[0].(ArObject).obj["__value__"].([]any)) { + return false, ArErr{} + } + for i, v := range arr { + res, err := runOperation(operationType{ + operation: 8, + values: []any{v, args[0].(ArObject).obj["__value__"].([]any)[i]}, + }, stack{}, 0) + if err.EXISTS { + return nil, err + } + if anyToBool(res) { + return false, ArErr{} + } + } + return true, ArErr{} + }} return val } diff --git a/src/built-in-functions.go b/src/built-in-functions.go index 11b3a22..1a0b309 100644 --- a/src/built-in-functions.go +++ b/src/built-in-functions.go @@ -10,6 +10,9 @@ type builtinFunc struct { } func ArgonString(args ...any) (any, ArErr) { + if len(args) == 0 { + return ArString(""), ArErr{} + } return ArString(anyToArgon(args[0], true, false, 3, 0, false, 0)), ArErr{} } diff --git a/src/built-ins.go b/src/built-ins.go index 0912747..0e2f323 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -145,6 +145,7 @@ func makeGlobal() ArObject { vars.obj["arccot"] = ArArccot vars.obj["todeg"] = ArToDeg vars.obj["torad"] = ArToRad + vars.obj["abs"] = ArAbs vars.obj["dir"] = builtinFunc{"dir", func(a ...any) (any, ArErr) { fmt.Println(a) if len(a) == 0 { diff --git a/src/map.go b/src/map.go index 248e5d7..08b616b 100644 --- a/src/map.go +++ b/src/map.go @@ -7,6 +7,13 @@ import ( var mapCompiled = makeRegex(`( *)\{(((( *).+( *):( *).+( *))|(` + spacelessVariable + `))(( *)\,(( *).+( *):( *).+( *))|(` + spacelessVariable + `)))*\}( *)`) +type createMap struct { + body anymap + code string + line int + path string +} + func isMap(code UNPARSEcode) bool { return mapCompiled.MatchString(code.code) } diff --git a/src/operations.go b/src/operations.go index 36a0526..3648826 100644 --- a/src/operations.go +++ b/src/operations.go @@ -4,7 +4,6 @@ import ( "fmt" "math" "reflect" - "strings" ) var operations = [][]string{ @@ -121,7 +120,6 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return false, err } @@ -139,6 +137,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { case 4: if isAnyNumber(resp) && isAnyNumber(resp2) { return resp.(number).Cmp(resp2.(number)) <= 0, ArErr{} + } else if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__LessThanEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{resp2}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} + } } return false, ArErr{ "Runtime Error", @@ -151,6 +164,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { case 5: if isAnyNumber(resp) && isAnyNumber(resp2) { return resp.(number).Cmp(resp2.(number)) >= 0, ArErr{} + } else if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__GreaterThanEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{resp2}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} + } } return false, ArErr{ "Runtime Error", @@ -163,6 +191,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { case 6: if isAnyNumber(resp) && isAnyNumber(resp2) { return resp.(number).Cmp(resp2.(number)) < 0, ArErr{} + } else if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__LessThan__"]; ok { + val, err := runCall( + call{ + y, + []any{resp2}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} + } } return false, ArErr{ "Runtime Error", @@ -175,6 +218,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { case 7: if isAnyNumber(resp) && isAnyNumber(resp2) { return resp.(number).Cmp(resp2.(number)) > 0, ArErr{} + } else if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__GreaterThan__"]; ok { + val, err := runCall( + call{ + y, + []any{resp2}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} + } } return false, ArErr{ "Runtime Error", @@ -185,9 +243,9 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { true, } case 8: - return !equals(resp, resp2), ArErr{} + return notequals(resp, resp2, o, stack, stacklevel) case 9: - return equals(resp, resp2), ArErr{} + return equals(resp, resp2, o, stack, stacklevel) default: return false, ArErr{ "Runtime Error", @@ -200,76 +258,75 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { } } -func calcNegative(o operationType, stack stack, stacklevel int) (number, ArErr) { - +func calcNegative(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( o.values[0], stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } - if !isAnyNumber(resp) { - return nil, ArErr{ - "Runtime Error", - "Cannot subtract from type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, - } + output := resp + if isAnyNumber(resp) { + output = newNumber().Set(resp.(number)) } - output := newNumber().Set(resp.(number)) for i := 1; i < len(o.values); i++ { resp, err := runVal( o.values[i], stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } - if typeof(resp) == "number" { - output = output.Sub(output, resp.(number)) - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot subtract type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + if typeof(output) == "number" && typeof(resp) == "number" { + output = output.(number).Sub(output.(number), resp.(number)) + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__Subtract__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue } } + return nil, ArErr{ + "Runtime Error", + "Cannot subtract type '" + typeof(resp) + "' from type '" + typeof(output) + "'", + o.line, + o.path, + o.code, + true, + } + } return output, ArErr{} } -func calcDivide(o operationType, stack stack, stacklevel int) (number, ArErr) { +func calcDivide(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( o.values[0], stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } - if !isAnyNumber(resp) { - return nil, ArErr{ - "Runtime Error", - "Cannot divide from type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, - } + output := resp + if isAnyNumber(resp) { + output = newNumber().Set(resp.(number)) } - output := newNumber().Set(resp.(number)) for i := 1; i < len(o.values); i++ { resp, err := runVal( o.values[i], @@ -280,18 +337,34 @@ func calcDivide(o operationType, stack stack, stacklevel int) (number, ArErr) { if err.EXISTS { return nil, err } - if typeof(resp) == "number" { - output = output.Quo(output, resp.(number)) - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot divide type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + if typeof(resp) == "number" && typeof(output) == "number" { + output = output.(number).Quo(output.(number), resp.(number)) + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__Divide__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue } } + return nil, ArErr{ + "Runtime Error", + "Cannot divide type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } return output, ArErr{} } @@ -303,14 +376,11 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } var output any = resp - if typeof(output) != "number" { - output = anyToArgon(resp, false, true, 3, 0, false, 0) - } else { + if typeof(output) == "number" { output = newNumber().Set(output.(number)) } for i := 1; i < len(o.values); i++ { @@ -319,21 +389,39 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } - if typeof(output) == "number" && typeof(resp) == "string" { - output = anyToArgon(output, false, true, 3, 0, false, 0) - } - if typeof(output) == "number" { + if typeof(output) == "number" && typeof(resp) == "number" { output = output.(number).Add(output.(number), resp.(number)) - } else { - output = output.(string) + anyToArgon(resp, false, true, 3, 0, false, 0) + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__Add__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue + } + } + return nil, ArErr{ + "Runtime Error", + "Cannot add type '" + typeof(resp) + "' to type '" + typeof(output) + "'", + o.line, + o.path, + o.code, + true, } - } - return AnyToArValid(output), ArErr{} + return (output), ArErr{} } func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { @@ -343,15 +431,12 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } var output any = resp - if typeof(output) != "number" { - output = anyToArgon(resp, false, true, 3, 0, false, 0) - } else { - output = newNumber().Set(output.(number)) + if isAnyNumber(resp) { + output = newNumber().Set(resp.(number)) } for i := 1; i < len(o.values); i++ { resp, err := runVal( @@ -359,28 +444,38 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } - if typeof(output) == "number" && typeof(resp) == "string" { - output = anyToArgon(output, false, true, 3, 0, false, 0) - } - if typeof(output) == "number" { + if typeof(output) == "number" && typeof(resp) == "number" { output = output.(number).Mul(output.(number), resp.(number)) - } else if typeof(resp) == "number" { - n, _ := resp.(number).Float64() - output = strings.Repeat(output.(string), int(n)) - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot multiply type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__Multiply__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue } } + return nil, ArErr{ + "Runtime Error", + "Cannot multiply type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } return output, ArErr{} } @@ -425,7 +520,7 @@ func calcOr(o operationType, stack stack, stacklevel int) (any, ArErr) { return output, ArErr{} } -func stringInSlice(a any, list []any) bool { +func InSlice(a any, list []any) bool { for _, b := range list { if b == a { return true @@ -433,8 +528,7 @@ func stringInSlice(a any, list []any) bool { } return false } - -func calcIn(o operationType, stack stack, stacklevel int) (bool, ArErr) { +func calcNotIn(o operationType, stack stack, stacklevel int) (any, ArErr) { if len(o.values) != 2 { return false, ArErr{ "Runtime Error", @@ -460,42 +554,125 @@ func calcIn(o operationType, stack stack, stacklevel int) (bool, ArErr) { stack, stacklevel+1, ) - resp2 = ArValidToAny(resp2) if err.EXISTS { return false, err } + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__NotContains__"]; ok { + return runCall( + call{ + y, + []any{resp2}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + } + } + return false, ArErr{ + "Runtime Error", + "Cannot check if type '" + typeof(resp) + "' is in type '" + typeof(resp2) + "'", + o.line, + o.path, + o.code, + true, + } +} - switch x := resp2.(type) { - case string: - check := anyToArgon(resp, false, true, 3, 0, false, 0) - return strings.Contains(x, check), ArErr{} - case []any: - return stringInSlice(resp, x), ArErr{} - case map[any]any: - _, ok := x[resp] - return ok, ArErr{} - default: +func calcIn(o operationType, stack stack, stacklevel int) (any, ArErr) { + if len(o.values) != 2 { return false, ArErr{ "Runtime Error", - "Cannot check if type '" + typeof(resp) + "' is in type '" + typeof(resp2) + "'", + "Invalid number of arguments for 'not in'", o.line, o.path, o.code, true, } } -} - -func equals(a any, b any) bool { - if typeof(a) == "number" && typeof(b) == "number" { - return a.(number).Cmp(b.(number)) == 0 - } else if typeof(a) == "string" || typeof(b) == "string" { - return anyToArgon(a, false, false, 3, 0, false, 0) == anyToArgon(b, false, false, 3, 0, false, 0) + resp, err := runVal( + o.values[0], + stack, + stacklevel+1, + ) + if err.EXISTS { + return false, err } - return reflect.DeepEqual(a, b) + + resp2, err := runVal( + o.values[1], + stack, + stacklevel+1, + ) + if err.EXISTS { + return false, err + } + if x, ok := resp2.(ArObject); ok { + if y, ok := x.obj["__Contains__"]; ok { + return runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + } + } + return false, ArErr{ + "Runtime Error", + "Cannot check if type '" + typeof(resp) + "' is in type '" + typeof(resp2) + "'", + o.line, + o.path, + o.code, + true, + } +} +func notequals(a any, b any, o operationType, stack stack, stacklevel int) (bool, ArErr) { + if typeof(a) == "number" && typeof(b) == "number" { + return a.(number).Cmp(b.(number)) != 0, ArErr{} + } else if x, ok := a.(ArObject); ok { + if y, ok := x.obj["__NotEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{b}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return !anyToBool(val), ArErr{} + } + } + return !reflect.DeepEqual(a, b), ArErr{} } -func calcMod(o operationType, stack stack, stacklevel int) (number, ArErr) { +func equals(a any, b any, o operationType, stack stack, stacklevel int) (bool, ArErr) { + if typeof(a) == "number" && typeof(b) == "number" { + return a.(number).Cmp(b.(number)) == 0, ArErr{} + } else if x, ok := a.(ArObject); ok { + if y, ok := x.obj["__Equal__"]; ok { + val, err := runCall( + call{ + y, + []any{b}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} + } + } + return reflect.DeepEqual(a, b), ArErr{} +} + +func calcMod(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( o.values[0], stack, @@ -505,17 +682,10 @@ func calcMod(o operationType, stack stack, stacklevel int) (number, ArErr) { if err.EXISTS { return nil, err } - if !isAnyNumber(resp) { - return nil, ArErr{ - "Runtime Error", - "Cannot calculate modulus from type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, - } + output := resp + if isAnyNumber(resp) { + output = newNumber().Set(resp.(number)) } - output := newNumber().Set(resp.(number)) for i := 1; i < len(o.values); i++ { resp, err := runVal( o.values[i], @@ -526,29 +696,91 @@ func calcMod(o operationType, stack stack, stacklevel int) (number, ArErr) { if err.EXISTS { return nil, err } - if typeof(resp) == "number" { - n1, _ := output.Float64() - n2, _ := resp.(number).Float64() - output = newNumber().SetFloat64(math.Mod(n1, n2)) - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot calculate modulus of type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + if typeof(resp) == "number" && typeof(output) == "number" { + output = floor(newNumber().Quo(resp.(number), output.(number))) + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__Modulo__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue } } + return nil, ArErr{ + "Runtime Error", + "Cannot calculate modulus of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } return output, ArErr{} } -func calcIntDiv(o operationType, stack stack, stacklevel int) (number, ArErr) { - resp, err := calcDivide(o, stack, stacklevel+1) - x, _ := resp.Float64() - resp = newNumber().SetFloat64(math.Trunc(x)) - return resp, err +func calcIntDiv(o operationType, stack stack, stacklevel int) (any, ArErr) { + resp, err := runVal( + o.values[0], + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err + } + output := resp + if isAnyNumber(resp) { + output = newNumber().Set(resp.(number)) + } + for i := 1; i < len(o.values); i++ { + resp, err := runVal( + o.values[i], + stack, + stacklevel+1, + ) + resp = ArValidToAny(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) == "number" && typeof(output) == "number" { + output = output.(number).Quo(output.(number), resp.(number)) + continue + } else if x, ok := output.(ArObject); ok { + if y, ok := x.obj["__IntDivide__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + output = val + continue + } + } + return nil, ArErr{ + "Runtime Error", + "Cannot divide type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } + return output, ArErr{} } func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { @@ -610,22 +842,10 @@ func runOperation(o operationType, stack stack, stacklevel int) (any, ArErr) { case 1: return calcOr(o, stack, stacklevel+1) case 2: - resp, err := calcIn(o, stack, stacklevel+1) - resp = !resp - return resp, err + return calcNotIn(o, stack, stacklevel+1) case 3: return calcIn(o, stack, stacklevel+1) - case 4: - return compareValues(o, stack, stacklevel+1) - case 5: - return compareValues(o, stack, stacklevel+1) - case 6: - return compareValues(o, stack, stacklevel+1) - case 7: - return compareValues(o, stack, stacklevel+1) - case 8: - return compareValues(o, stack, stacklevel+1) - case 9: + case 4, 5, 6, 7, 8, 9: return compareValues(o, stack, stacklevel+1) case 10: return calcAdd(o, stack, stacklevel+1) diff --git a/src/run.go b/src/run.go index 00658ae..0d509a2 100644 --- a/src/run.go +++ b/src/run.go @@ -14,8 +14,6 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) { stackoverflow = stacklevel >= 10000 ) switch x := line.(type) { - case number: - return x, ArErr{} case string: return ArString(x), ArErr{} case call: @@ -191,11 +189,15 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) { break } return runImport(x, stack, stacklevel+1) - case bool: - return x, ArErr{} - case nil: - return x, ArErr{} - case ArObject: + case ABS: + if stackoverflow { + linenum = x.line + path = x.path + code = x.code + break + } + return runAbs(x, stack, stacklevel+1) + case bool, ArObject, number, nil: return x, ArErr{} } if stackoverflow { diff --git a/src/sortany.go b/src/sortany.go index b9a48aa..c090a77 100644 --- a/src/sortany.go +++ b/src/sortany.go @@ -32,7 +32,7 @@ func quickSort(list []interface{}, getKey func(interface{}) (interface{}, ArErr) EXISTS: true, } } - if comp < 0 { + if comp { left = append(left, v) } else { right = append(right, v) @@ -52,35 +52,32 @@ func quickSort(list []interface{}, getKey func(interface{}) (interface{}, ArErr) } func getkeyCache(getKey func(interface{}) (interface{}, ArErr), index interface{}, cache keyCache) (interface{}, ArErr) { - if cacheval, ok := cache[index]; ok { + key := ArValidToAny(index) + if cacheval, ok := cache[key]; ok { return cacheval, ArErr{} } val, err := getKey(index) if err.EXISTS { return nil, err } - cache[index] = val + cache[key] = 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) +func compare(a, b any) (bool, error) { + if isAnyNumber(a) && isAnyNumber(b) { + return a.(number).Cmp(b.(number)) < 0, nil + } else if x, ok := a.(ArObject); ok { + if y, ok := x.obj["__LessThan__"]; ok { + resp, err := runCall( + call{ + callable: y, + args: []any{b}, + }, stack{}, 0) + if !err.EXISTS { + return anyToBool(resp), nil + } } - 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) + return false, fmt.Errorf("cannot compare %s to %s", typeof(a), typeof(b)) } diff --git a/src/string.go b/src/string.go index 759d1f9..2fe649c 100644 --- a/src/string.go +++ b/src/string.go @@ -30,8 +30,7 @@ func unquoted( if err != nil { return "", err } - classoutput := (output) - return classoutput, nil + return output, nil } // returns translateString, success, error @@ -256,8 +255,8 @@ func ArString(str string) ArObject { } splitby := a[0].(string) output := []any{} - splitted := any(strings.Split(str, splitby)) - for _, v := range splitted.([]string) { + splitted := (strings.Split(str, splitby)) + for _, v := range splitted { output = append(output, ArString(v)) } return output, ArErr{} @@ -412,5 +411,134 @@ func ArString(str string) ArObject { } return strings.TrimRight(str, cutset), ArErr{} }} + obj.obj["__LessThanEqual__"] = builtinFunc{ + "__LessThanOrEqual__", + 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", "cannot get less than or equal to of type " + typeof(a[0]) + " from string", 0, "", "", true} + } + return str <= a[0].(string), ArErr{} + }} + obj.obj["__LessThan__"] = builtinFunc{ + "__LessThan__", + 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", "cannot get less than of type " + typeof(a[0]) + " from string", 0, "", "", true} + } + return str < a[0].(string), ArErr{} + }} + obj.obj["__GreaterThan__"] = builtinFunc{ + "__GreaterThan__", + 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", "cannot get greater than of type " + typeof(a[0]) + " from string", 0, "", "", true} + } + return str > a[0].(string), ArErr{} + }} + + obj.obj["__GreaterThanEqual__"] = builtinFunc{ + "__GreaterThanEqual__", + 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", "cannot get greater than or equal to of type " + typeof(a[0]) + " from string", 0, "", "", true} + } + return str >= a[0].(string), ArErr{} + }} + obj.obj["__Equal__"] = builtinFunc{ + "__Equal__", + func(a ...any) (any, ArErr) { + if len(a) != 1 { + return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true} + } + return str == a[0], ArErr{} + }} + obj.obj["__NotEqual__"] = builtinFunc{ + "__NotEqual__", + func(a ...any) (any, ArErr) { + if len(a) != 1 { + return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true} + } + return str != a[0], ArErr{} + }} + obj.obj["__Add__"] = builtinFunc{ + "__Add__", + 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", "cannot add " + typeof(a[0]) + " to string", 0, "", "", true} + } + return strings.Join([]string{str, a[0].(string)}, ""), ArErr{} + }} + obj.obj["__Multiply__"] = builtinFunc{ + "__Multiply__", + 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]) != "number" { + return nil, ArErr{"TypeError", "cannot multiply string by " + typeof(a[0]), 0, "", "", true} + } + n := a[0].(number) + if !n.IsInt() { + return nil, ArErr{"ValueError", "cannot multiply string by float", 0, "", "", true} + } + if n.Sign() < 0 { + return nil, ArErr{"ValueError", "cannot multiply string by negative number", 0, "", "", true} + } + return strings.Repeat(str, int(n.Num().Int64())), 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", "cannot check if string contains " + typeof(a[0]), 0, "", "", true} + } + return strings.Contains(str, a[0].(string)), ArErr{} + }} + obj.obj["__Subtract__"] = builtinFunc{ + "__Subtract__", + 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", "cannot subtract " + typeof(a[0]) + " from string", 0, "", "", true} + } + return strings.Replace(str, a[0].(string), "", -1), ArErr{} + }} + obj.obj["__Divide__"] = builtinFunc{ + "__Divide__", + 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", "cannot divide string by " + typeof(a[0]), 0, "", "", true} + } + splitby := a[0].(string) + output := []any{} + splitted := (strings.Split(str, splitby)) + for _, v := range splitted { + output = append(output, ArString(v)) + } + return ArArray(output), ArErr{} + }} return obj } diff --git a/src/translate.go b/src/translate.go index c501a26..d2e3257 100644 --- a/src/translate.go +++ b/src/translate.go @@ -63,6 +63,12 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i return resp, worked, err, i } } + if isAbs(code) { + resp, worked, err, i = parseAbs(code, index, codelines) + if worked { + return resp, worked, err, i + } + } if isnot(code) { return parseNot(code, index, codelines, isLine) } @@ -80,8 +86,6 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i } if isNumber(code) { return parseNumber(code) - } else if isNegative(code) { - return parseNegative(code, index, codelines) } else if isString(code) { return parseString(code) } else if issquareroot(code) { @@ -106,7 +110,9 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i return nil, worked, err, step } } - if isCall(code) { + if isNegative(code) { + return parseNegative(code, index, codelines) + } else if isCall(code) { resp, worked, err, i = parseCall(code, index, codelines) if worked { return resp, worked, err, i