diff --git a/modules/csv/init.ar b/argon_modules/csv/init.ar similarity index 100% rename from modules/csv/init.ar rename to argon_modules/csv/init.ar diff --git a/modules/this.ar b/argon_modules/this.ar similarity index 100% rename from modules/this.ar rename to argon_modules/this.ar diff --git a/modules/welcome.ar b/argon_modules/welcome.ar similarity index 100% rename from modules/welcome.ar rename to argon_modules/welcome.ar 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 81baebc..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{} @@ -163,6 +190,26 @@ func makeGlobal() ArObject { for key := range x.obj { newarray = append(newarray, key) } + if callable, ok := x.obj["__dir__"]; ok { + resp, err := runCall( + call{ + callable: callable, + args: []any{}, + }, + stack{newscope()}, + 0, + ) + if err.EXISTS { + return nil, err + } + resp = ArValidToAny(resp) + switch x := resp.(type) { + case []any: + newarray = append(newarray, x...) + default: + return nil, ArErr{TYPE: "TypeError", message: "__dir__ returned type '" + typeof(x) + "'", EXISTS: true} + } + } return ArArray(newarray), ArErr{} } 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/import.go b/src/import.go index e3a34e1..d7d6fd2 100644 --- a/src/import.go +++ b/src/import.go @@ -11,6 +11,8 @@ import ( var imported = make(map[string]ArObject) var importing = make(map[string]bool) +var modules_folder = "argon_modules" + func FileExists(filename string) bool { if _, err := os.Stat(filename); err == nil { return true @@ -73,13 +75,13 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb pathsToTest = []string{ filepath.Join(origin, realpath, "init.ar"), filepath.Join(origin, path), - filepath.Join(origin, "modules", path), - filepath.Join(origin, "modules", realpath, "init.ar"), + filepath.Join(origin, modules_folder, path), + filepath.Join(origin, modules_folder, realpath, "init.ar"), filepath.Join(ex, path), - filepath.Join(ex, "modules", realpath, "init.ar"), - filepath.Join(ex, "modules", path), - filepath.Join(executable, "modules", realpath, "init.ar"), - filepath.Join(executable, "modules", path), + filepath.Join(ex, modules_folder, realpath, "init.ar"), + filepath.Join(ex, modules_folder, path), + filepath.Join(executable, modules_folder, realpath, "init.ar"), + filepath.Join(executable, modules_folder, path), } } 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 be38b83..17a0212 100644 --- a/src/map.go +++ b/src/map.go @@ -6,7 +6,7 @@ import ( "sync" ) -var mapCompiled = makeRegex(`( *)\{(((( *).+( *):( *).+( *))|(` + spacelessVariable + `))(( *)\,(( *).+( *):( *).+( *))|(` + spacelessVariable + `)))*\}( *)`) +var mapCompiled = makeRegex(`( )*{( |\n)*(((.|\n)+)(,(.|\n)+)*)?( |\n)*}( )*`) type createMap struct { body anymap @@ -19,11 +19,11 @@ func isMap(code UNPARSEcode) bool { return mapCompiled.MatchString(code.code) } -func parseMap(code UNPARSEcode) (any, UNPARSEcode) { - trimmed := strings.Trim(code.code, " ") +func parseMap(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { + trimmed := strings.TrimSpace(code.code) trimmed = trimmed[1 : len(trimmed)-1] debugPrintln(trimmed) - return nil, UNPARSEcode{} + return Map(anymap{}), true, ArErr{}, 1 } func Map(m anymap) ArObject { @@ -211,5 +211,14 @@ func Map(m anymap) ArObject { return true, ArErr{} }, } + obj.obj["__dir__"] = builtinFunc{ + "__dir__", + func(args ...any) (any, ArErr) { + x := []any{} + for k := range m { + x = append(x, k) + } + return x, ArErr{} + }} return obj } diff --git a/src/operations.go b/src/operations.go index 79153f6..fd5212c 100644 --- a/src/operations.go +++ b/src/operations.go @@ -66,9 +66,6 @@ func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (oper continue } for k := 0; k < len(split)-1; k++ { - if len(strings.TrimSpace(split[k])) == 0 || len(strings.TrimSpace(split[k+1])) == 0 { - break - } val1, worked, err, step1 := translateVal(UNPARSEcode{ code: strings.Join(split[:k+1], operations[i][j]), realcode: code.realcode, @@ -79,6 +76,9 @@ func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (oper if k == len(split)-1 { return operationType{}, false, err, 0 } else { + if len(strings.TrimSpace(split[k])) == 0 || len(strings.TrimSpace(split[k+1])) == 0 { + break + } continue } } @@ -93,6 +93,9 @@ func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (oper if k == len(split)-1 { return operationType{}, false, err, 0 } else { + if len(strings.TrimSpace(split[k])) == 0 || len(strings.TrimSpace(split[k+1])) == 0 { + break + } continue } } @@ -143,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 } @@ -170,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 } @@ -197,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{ @@ -224,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 } @@ -287,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 } @@ -339,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{ @@ -459,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{ @@ -508,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 } @@ -520,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 } @@ -641,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{} @@ -664,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 } @@ -712,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{ @@ -764,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{ @@ -781,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, @@ -846,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 c45307f..6ce65ea 100644 --- a/src/to-argon.go +++ b/src/to-argon.go @@ -74,6 +74,8 @@ 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 "{}" diff --git a/src/translate.go b/src/translate.go index 89c3ab9..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) @@ -103,6 +110,8 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i if worked { return resp, worked, err, i } + } else if isMap(code) { + resp, worked, err, i = parseMap(code, index, codelines) } { operation, worked, err, step := parseOperations(code, index, codelines) 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,