From 3bf48079d513e2892bb08dcfe9c5cc39065cec1b Mon Sep 17 00:00:00 2001 From: William Bell Date: Mon, 19 Jun 2023 23:58:34 +0100 Subject: [PATCH] add colour object --- src/boolean.go | 13 ++- src/built-ins.go | 27 +++++ src/colour.go | 96 ++++++++++++++++++ src/infinity.go | 1 + src/map.go | 4 +- src/operations.go | 249 ++++++++++++++++++++++++++++++++++++++++------ src/to-argon.go | 6 +- src/translate.go | 13 ++- src/variable.go | 3 +- 9 files changed, 370 insertions(+), 42 deletions(-) create mode 100644 src/colour.go create mode 100644 src/infinity.go diff --git a/src/boolean.go b/src/boolean.go index c93d9e7..728d711 100644 --- a/src/boolean.go +++ b/src/boolean.go @@ -13,7 +13,18 @@ func anyToBool(x any) bool { case nil: return false case ArObject: - return anyToBool(ArValidToAny(x)) + if y, ok := x.obj["__Boolean__"]; ok { + val, err := runCall( + call{ + callable: y, + args: []any{}, + }, stack{}, 0) + if err.EXISTS { + return false + } + return anyToBool(val) + } + return false case builtinFunc: return true case Callable: diff --git a/src/built-ins.go b/src/built-ins.go index 6cf3d52..bcf976d 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -150,8 +150,35 @@ func makeGlobal() ArObject { vars["cot"] = ArCot vars["arccot"] = ArArccot vars["todeg"] = ArToDeg + vars["colour"] = ArColour vars["torad"] = ArToRad vars["abs"] = ArAbs + vars["fraction"] = builtinFunc{"fraction", func(a ...any) (any, ArErr) { + if len(a) == 0 { + return nil, ArErr{TYPE: "fraction", message: "fraction takes 1 argument", + EXISTS: true} + } + switch x := a[0].(type) { + case number: + return ArString(x.String()), ArErr{} + case ArObject: + if callable, ok := x.obj["__fraction__"]; ok { + resp, err := runCall( + call{ + callable: callable, + args: []any{}, + }, + stack{}, + 0, + ) + if err.EXISTS { + return nil, err + } + return resp, ArErr{} + } + } + return nil, ArErr{TYPE: "TypeError", message: "Cannot fraction '" + typeof(a[0]) + "'", EXISTS: true} + }} vars["dir"] = builtinFunc{"dir", func(a ...any) (any, ArErr) { if len(a) == 0 { return ArArray([]any{}), ArErr{} diff --git a/src/colour.go b/src/colour.go new file mode 100644 index 0000000..5a9c308 --- /dev/null +++ b/src/colour.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + + "github.com/fatih/color" + "github.com/jwalton/go-supportscolor" +) + +var ArColour = Map( + anymap{ + "set": builtinFunc{"set", func(a ...any) (any, ArErr) { + if len(a) != 2 { + return nil, ArErr{ + TYPE: "TypeError", + message: "set() takes exactly 2 argument (" + fmt.Sprint(len(a)) + " given)", + EXISTS: true, + } + } + var c *color.Color + var s string + if x, ok := a[0].(number); ok { + c = color.Set(color.Attribute(x.Num().Int64())) + } else { + return nil, ArErr{ + TYPE: "TypeError", + message: "set() argument 1 must be an number, not " + typeof(a[0]), + EXISTS: true, + } + } + if typeof(a[1]) == "string" { + s = ArValidToAny(a[1]).(string) + } else { + return nil, ArErr{ + TYPE: "TypeError", + message: "set() argument 2 must be a string, not " + typeof(a[1]), + EXISTS: true, + } + } + if supportscolor.Stdout().SupportsColor { + return c.Sprint(s), ArErr{} + } else { + return s, ArErr{} + } + }}, + "bg": Map( + anymap{ + "black": newNumber().SetInt64(int64(color.BgBlack)), + "red": newNumber().SetInt64(int64(color.BgRed)), + "green": newNumber().SetInt64(int64(color.BgGreen)), + "yellow": newNumber().SetInt64(int64(color.BgYellow)), + "blue": newNumber().SetInt64(int64(color.BgBlue)), + "magenta": newNumber().SetInt64(int64(color.BgMagenta)), + "cyan": newNumber().SetInt64(int64(color.BgCyan)), + "white": newNumber().SetInt64(int64(color.BgWhite)), + "hiBlack": newNumber().SetInt64(int64(color.BgHiBlack)), + "hiRed": newNumber().SetInt64(int64(color.BgHiRed)), + "hiGreen": newNumber().SetInt64(int64(color.BgHiGreen)), + "hiYellow": newNumber().SetInt64(int64(color.BgHiYellow)), + "hiBlue": newNumber().SetInt64(int64(color.BgHiBlue)), + "hiMagenta": newNumber().SetInt64(int64(color.BgHiMagenta)), + "hiCyan": newNumber().SetInt64(int64(color.BgHiCyan)), + "hiWhite": newNumber().SetInt64(int64(color.BgHiWhite)), + }, + ), + "fg": Map( + anymap{ + "black": newNumber().SetInt64(int64(color.FgBlack)), + "red": newNumber().SetInt64(int64(color.FgRed)), + "green": newNumber().SetInt64(int64(color.FgGreen)), + "yellow": newNumber().SetInt64(int64(color.FgYellow)), + "blue": newNumber().SetInt64(int64(color.FgBlue)), + "magenta": newNumber().SetInt64(int64(color.FgMagenta)), + "cyan": newNumber().SetInt64(int64(color.FgCyan)), + "white": newNumber().SetInt64(int64(color.FgWhite)), + "hiBlack": newNumber().SetInt64(int64(color.FgHiBlack)), + "hiRed": newNumber().SetInt64(int64(color.FgHiRed)), + "hiGreen": newNumber().SetInt64(int64(color.FgHiGreen)), + "hiYellow": newNumber().SetInt64(int64(color.FgHiYellow)), + "hiBlue": newNumber().SetInt64(int64(color.FgHiBlue)), + "hiMagenta": newNumber().SetInt64(int64(color.FgHiMagenta)), + "hiCyan": newNumber().SetInt64(int64(color.FgHiCyan)), + "hiWhite": newNumber().SetInt64(int64(color.FgHiWhite)), + }, + ), + "reset": newNumber().SetInt64(int64(color.Reset)), + "bold": newNumber().SetInt64(int64(color.Bold)), + "faint": newNumber().SetInt64(int64(color.Faint)), + "italic": newNumber().SetInt64(int64(color.Italic)), + "underline": newNumber().SetInt64(int64(color.Underline)), + "blinkSlow": newNumber().SetInt64(int64(color.BlinkSlow)), + "blinkRapid": newNumber().SetInt64(int64(color.BlinkRapid)), + "reverseVideo": newNumber().SetInt64(int64(color.ReverseVideo)), + "concealed": newNumber().SetInt64(int64(color.Concealed)), + "crossedOut": newNumber().SetInt64(int64(color.CrossedOut)), + }) diff --git a/src/infinity.go b/src/infinity.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/src/infinity.go @@ -0,0 +1 @@ +package main diff --git a/src/map.go b/src/map.go index 7fc754f..17a0212 100644 --- a/src/map.go +++ b/src/map.go @@ -6,7 +6,7 @@ import ( "sync" ) -var mapCompiled = makeRegex(`( )*<( |\n)*(((.|\n)+)(,(.|\n)+)*)?( |\n)*>( )*`) +var mapCompiled = makeRegex(`( )*{( |\n)*(((.|\n)+)(,(.|\n)+)*)?( |\n)*}( )*`) type createMap struct { body anymap @@ -20,7 +20,7 @@ func isMap(code UNPARSEcode) bool { } func parseMap(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { - trimmed := strings.Trim(code.code, " ") + trimmed := strings.TrimSpace(code.code) trimmed = trimmed[1 : len(trimmed)-1] debugPrintln(trimmed) return Map(anymap{}), true, ArErr{}, 1 diff --git a/src/operations.go b/src/operations.go index f7c19a1..fd5212c 100644 --- a/src/operations.go +++ b/src/operations.go @@ -146,6 +146,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return anyToBool(val), ArErr{} + } + } + } + if x, ok := resp2.(ArObject); ok { + if y, ok := x.obj["__GreaterThanEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return false, err } @@ -173,6 +188,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return anyToBool(val), ArErr{} + } + } + } + if x, ok := resp2.(ArObject); ok { + if y, ok := x.obj["__LessThanEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return false, err } @@ -200,10 +230,25 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { o.line, o.path, }, stack, stacklevel+1) - if err.EXISTS { - return false, err + if !err.EXISTS { + return anyToBool(val), ArErr{} + } + } + if x, ok := resp2.(ArObject); ok { + if y, ok := x.obj["__GreaterThan__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return false, err + } + return anyToBool(val), ArErr{} } - return anyToBool(val), ArErr{} } } return false, ArErr{ @@ -227,6 +272,21 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return anyToBool(val), ArErr{} + } + } + } + if x, ok := resp2.(ArObject); ok { + if y, ok := x.obj["__LessThan__"]; ok { + val, err := runCall( + call{ + y, + []any{resp}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return false, err } @@ -290,6 +350,21 @@ func calcNegative(o operationType, stack stack, stacklevel int) (any, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return val, ArErr{} + } + } + } + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostSubtract__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return nil, err } @@ -342,11 +417,26 @@ func calcDivide(o operationType, stack stack, stacklevel int) (any, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return val, ArErr{} + } + } + } + + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostDivide__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return nil, err } - output = val - return output, ArErr{} + return val, ArErr{} } } return nil, ArErr{ @@ -462,11 +552,26 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + output = val + return output, ArErr{} + } + } + } + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostMultiply__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return nil, err } - output = val - return output, ArErr{} + return val, ArErr{} } } return nil, ArErr{ @@ -511,7 +616,6 @@ func calcOr(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -523,7 +627,6 @@ func calcOr(o operationType, stack stack, stacklevel int) (any, ArErr) { stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return nil, err } @@ -644,10 +747,25 @@ func notequals(a any, b any, o operationType, stack stack, stacklevel int) (bool o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return !anyToBool(val), ArErr{} + } + } + } + if x, ok := b.(ArObject); ok { + if y, ok := x.obj["__NotEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{a}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return false, err } - return !anyToBool(val), ArErr{} + return anyToBool(val), ArErr{} } } return !reflect.DeepEqual(a, b), ArErr{} @@ -667,6 +785,21 @@ func equals(a any, b any, o operationType, stack stack, stacklevel int) (bool, A o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + return anyToBool(val), ArErr{} + } + } + } + if x, ok := b.(ArObject); ok { + if y, ok := x.obj["__GreaterThanEqual__"]; ok { + val, err := runCall( + call{ + y, + []any{a}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return false, err } @@ -715,11 +848,27 @@ func calcMod(o operationType, stack stack, stacklevel int) (any, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + output = val + return output, ArErr{} + } + } + } + + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostModulo__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return nil, err } - output = val - return output, ArErr{} + return val, ArErr{} } } return nil, ArErr{ @@ -767,11 +916,26 @@ func calcIntDiv(o operationType, stack stack, stacklevel int) (any, ArErr) { o.line, o.path, }, stack, stacklevel+1) + if !err.EXISTS { + output = val + return output, ArErr{} + } + } + } + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostIntDivide__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) if err.EXISTS { return nil, err } - output = val - return output, ArErr{} + return val, ArErr{} } } return nil, ArErr{ @@ -784,7 +948,7 @@ func calcIntDiv(o operationType, stack stack, stacklevel int) (any, ArErr) { } } -func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { +func calcPower(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( o.value1, stack, @@ -849,26 +1013,47 @@ func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { } output.Mul(output, calculated) } - - /* - n1, _ := output.Float64() - n2, _ := resp.(number).Float64() - output = newNumber().SetFloat64(math.Pow(n1, n2)) - if output == nil { - output = infinity + return output, ArErr{} + } else if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__Power__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if !err.EXISTS { + return val, ArErr{} } - */ - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot calculate power of type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, } } - return output, ArErr{} + + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostPower__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if err.EXISTS { + return nil, err + } + return val, ArErr{} + } + } + return nil, ArErr{ + "Runtime Error", + "Cannot calculate power of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } func runOperation(o operationType, stack stack, stacklevel int) (any, ArErr) { diff --git a/src/to-argon.go b/src/to-argon.go index d174825..6ce65ea 100644 --- a/src/to-argon.go +++ b/src/to-argon.go @@ -74,9 +74,11 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored if colored { output = append(output, "\x1b[0m") } + case ArObject: + case anymap: if len(x) == 0 { - return "<>" + return "{}" } keys := make([]any, len(x)) sort.Slice(keys, func(i, j int) bool { @@ -107,7 +109,7 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored } 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)) + ">" + return "{" + maybenewline + (strings.Repeat(" ", (indent+1)*plain)) + strings.Join(output, ","+maybenewline+(strings.Repeat(" ", (indent+1)*plain))) + maybenewline + (strings.Repeat(" ", indent*plain)) + "}" case []any: singleline := len(x) <= 3 output := []string{} diff --git a/src/translate.go b/src/translate.go index e5e70c3..3a4c92b 100644 --- a/src/translate.go +++ b/src/translate.go @@ -91,9 +91,16 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i } else if isString(code) { return parseString(code) } else if issquareroot(code) { - return parseSquareroot(code, index, codelines) - } else if isFactorial(code) { - return parseFactorial(code, index, codelines) + resp, worked, err, i = parseSquareroot(code, index, codelines) + if worked { + return resp, worked, err, i + } + } + if isFactorial(code) { + resp, worked, err, i = parseFactorial(code, index, codelines) + if worked { + return resp, worked, err, i + } } if isVariable(code) { return parseVariable(code) diff --git a/src/variable.go b/src/variable.go index aca7d7f..125d12a 100644 --- a/src/variable.go +++ b/src/variable.go @@ -275,10 +275,9 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) { case ArObject: if _, ok := y.obj["__setindex__"]; ok { callable := y.obj["__setindex__"] - r := ArValidToAny(resp) _, err := runCall(call{ callable: callable, - args: []any{key, r}, + args: []any{key, resp}, line: v.line, path: v.path, code: v.code,