From 14ae68b9d1afd0a39863c9171c3205c4335569cf Mon Sep 17 00:00:00 2001 From: Ugric Date: Sun, 18 Jun 2023 01:20:21 +0100 Subject: [PATCH] fix operation translation taking ages --- .vscode/settings.json | 5 + build.bat | 2 +- debug.bat | 6 + debug_build.bat | 2 + example.ar | 2 - modules/welcome.ar | 76 ++++ src/array.go | 6 +- src/boolean.go | 5 +- src/debug.go | 26 +- src/input.go | 6 + src/main.go | 2 +- src/map.go | 3 +- src/negative.go | 11 +- src/operations.go | 779 ++++++++++++++++++++-------------------- src/string.go | 12 + src/term-class.go | 13 +- src/translate.go | 1 + test.ar | 1 - testingoop.py | 21 ++ tests/brainfuck.ar | 6 +- tests/csv_test.ar | 2 +- tests/diff.ar | 14 +- tests/memoryLeakTest.ar | 7 +- tests/welcomemessage.ar | 9 - 24 files changed, 576 insertions(+), 441 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 debug.bat create mode 100644 debug_build.bat delete mode 100644 example.ar create mode 100644 modules/welcome.ar delete mode 100644 test.ar create mode 100644 testingoop.py delete mode 100644 tests/welcomemessage.ar diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5d25211 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.ar": "lua" + } +} diff --git a/build.bat b/build.bat index 9af9c18..e0913a5 100644 --- a/build.bat +++ b/build.bat @@ -1,2 +1,2 @@ @echo off -go build -o bin/argon.exe ./src \ No newline at end of file +go build -trimpath -ldflags="-s -w" -o bin/argon.exe ./src \ No newline at end of file diff --git a/debug.bat b/debug.bat new file mode 100644 index 0000000..351ac1c --- /dev/null +++ b/debug.bat @@ -0,0 +1,6 @@ +@echo off + +:: run the go run command passing the path to the main.go file, with the working directory set to the bin folder. pass in the arguments + +set __ARGON_DEBUG__=true +go run ./src %* \ No newline at end of file diff --git a/debug_build.bat b/debug_build.bat new file mode 100644 index 0000000..121c834 --- /dev/null +++ b/debug_build.bat @@ -0,0 +1,2 @@ +@echo off +go build -o bin/debug_argon.exe ./src \ No newline at end of file diff --git a/example.ar b/example.ar deleted file mode 100644 index 265b901..0000000 --- a/example.ar +++ /dev/null @@ -1,2 +0,0 @@ -forever do - term.log(random()) \ No newline at end of file diff --git a/modules/welcome.ar b/modules/welcome.ar new file mode 100644 index 0000000..1e99dc2 --- /dev/null +++ b/modules/welcome.ar @@ -0,0 +1,76 @@ +term.log(" ____ ") +term.log(" /\\ |___ \\ ") +term.log(" / \\ _ __ __ _ ___ _ __ __ ____) |") +term.log(" / /\\ \\ | '__/ _` |/ _ \\| '_ \\ \\ \\ / /__ < ") +term.log(" / ____ \\| | | (_| | (_) | | | | \\ V /___) |") +term.log(" /_/ \\_\\_| \\__, |\\___/|_| |_| \\_/|____/ ") +term.log(" __/ | ") +term.log(" |___/ ") +term.log("----------------------------------------------") +term.log("Welcome to ARGON!") + +input.pause() +term.clear() + +# ARGON 3 is a math-driven programming language designed to make code easy to read and write. It's not meant to be fast, as it's interpreted. This specification should be used as a guideline, and is subject to change for later versions. Later updates for Argon 3 should be backwards compatible (where possible) with code designed for older versions of the interpreter. + +term.log("ARGON 3 is a math-driven programming language") +term.log("designed to make code easy to read and write.") +term.log("It's not meant to be fast, as it's interpreted.") +term.log("This specification should be used as a guideline,") +term.log("and is subject to change for later versions.") +term.log("Later updates for Argon 3 should be backwards") +term.log("compatible (where possible) with code designed") +term.log("for older versions of the interpreter.") +term.log() +input.pause() +term.clear() + +term.log("📚 Features") +term.log(" - Easy to read and write: Argon 3 is designed with clarity of code in mind, making it easier for you and others to read and write code.") +term.log(" - All numbers are stored as rational numbers, preventing precision errors.") +term.log(" - Math-driven: Designed for mathematical computations, Argon 3 uses techniques and rules set in maths. It's designed to be easy for mathematicians to write and understand algorithms in.") +term.log(" - Interpreted: Argon 3 is an interpreted language, so you don't need to compile your code before running it.") +term.log(" - Cross-platform: Argon 3 can be run on any platform that has an interpreter for it.") +term.log(" - Lightweight: The Argon 3 interpreter is small and doesn't require a lot of system resources to run.") + +term.log() +input.pause() +term.clear() + +term.log("🚀 Example Code") +term.log() +term.log("Here's an example of how to define a function in Argon 3:") +term.log() +term.log("f(x) = x^2 + 2*x + 1") +term.log("term.log('f(10) =', f(10))") +term.log("\n") +input.pause() +term.clear() + +# license: MIT +term.log("📜 License") +term.log() +term.log("MIT License\n\nCopyright (c) 2022 Open Argon") +term.log() +term.log("Permission is hereby granted, free of charge, to any person obtaining a copy") +term.log("of this software and associated documentation files (the \"Software\"), to deal") +term.log("in the Software without restriction, including without limitation the rights") +term.log("to use, copy, modify, merge, publish, distribute, sublicense, and/or sell") +term.log("copies of the Software, and to permit persons to whom the Software is") +term.log("furnished to do so, subject to the following conditions:") +term.log("The above copyright notice and this permission notice shall be included in all") +term.log("copies or substantial portions of the Software.") +term.log() +term.log("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR") +term.log("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,") +term.log("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE") +term.log("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER") +term.log("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,") +term.log("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE") +term.log("SOFTWARE.") +term.log() +term.log("remember this is subject to change and this version is not guaranteed to be up to date,\nalways check the latest version of the license agreement at https://raw.githubusercontent.com/Open-Argon/argon-v3/master/licence") +term.log() +input.pause() +term.clear() \ No newline at end of file diff --git a/src/array.go b/src/array.go index 2365898..761bba7 100644 --- a/src/array.go +++ b/src/array.go @@ -551,7 +551,8 @@ func ArArray(arr []any) ArObject { for i, v := range arr { res, err := runOperation(operationType{ operation: 8, - values: []any{v, args[0].(ArObject).obj["__value__"].([]any)[i]}, + value1: v, + value2: args[0].(ArObject).obj["__value__"].([]any)[i], }, stack{}, 0) if err.EXISTS { return nil, err @@ -575,7 +576,8 @@ func ArArray(arr []any) ArObject { for _, v := range arr { res, err := runOperation(operationType{ operation: 8, - values: []any{v, args[0]}, + value1: v, + value2: args[0], }, stack{}, 0) if err.EXISTS { return nil, err diff --git a/src/boolean.go b/src/boolean.go index b545f25..c93d9e7 100644 --- a/src/boolean.go +++ b/src/boolean.go @@ -13,10 +13,7 @@ func anyToBool(x any) bool { case nil: return false case ArObject: - if typeof(x) == "array" { - return len(x.obj["__value__"].([]any)) != 0 - } - return len(x.obj) != 0 + return anyToBool(ArValidToAny(x)) case builtinFunc: return true case Callable: diff --git a/src/debug.go b/src/debug.go index 3d3743a..37dbf03 100644 --- a/src/debug.go +++ b/src/debug.go @@ -3,19 +3,41 @@ package main import ( "fmt" "os" + "sync" ) var debug = os.Getenv("__ARGON_DEBUG__") == "true" -func debugPrintln(a ...any) { +var __debugPrints = [][]any{} +var __debugPrintsLock = sync.RWMutex{} + +func debugInit() { if debug { + fmt.Println("In debug mode...") go func() { defer func() { if r := recover(); r != nil { fmt.Println("debugPrintln: panic:", r) } }() - fmt.Println(a...) + for { + __debugPrintsLock.RLock() + for _, v := range __debugPrints { + fmt.Println(v...) + } + __debugPrintsLock.RUnlock() + __debugPrintsLock.Lock() + __debugPrints = [][]any{} + __debugPrintsLock.Unlock() + } }() } } + +func debugPrintln(a ...any) { + if debug { + __debugPrintsLock.Lock() + __debugPrints = append(__debugPrints, a) + __debugPrintsLock.Unlock() + } +} diff --git a/src/input.go b/src/input.go index adf7d69..612e9b1 100644 --- a/src/input.go +++ b/src/input.go @@ -58,3 +58,9 @@ func getPassword(args ...any) (string, error) { fmt.Print("\r") return string(password), nil } + +func pause() { + fmt.Print("Press any key to continue...") + term.ReadPassword(int(os.Stdin.Fd())) + fmt.Println() +} diff --git a/src/main.go b/src/main.go index a200b27..a24d2e6 100644 --- a/src/main.go +++ b/src/main.go @@ -15,7 +15,7 @@ func newscope() ArObject { } func main() { - debugPrintln("In debug mode...") + debugInit() if !debug { defer func() { diff --git a/src/map.go b/src/map.go index 4547213..be38b83 100644 --- a/src/map.go +++ b/src/map.go @@ -196,7 +196,8 @@ func Map(m anymap) ArObject { } val, err := runOperation(operationType{ operation: 9, - values: []any{v, a[k]}, + value1: v, + value2: a[k], }, stack{}, 0) if err.EXISTS { return val, err diff --git a/src/negative.go b/src/negative.go index 98a2257..1bfb23f 100644 --- a/src/negative.go +++ b/src/negative.go @@ -15,13 +15,20 @@ func isNegative(code UNPARSEcode) bool { return negativeCompile.MatchString(code.code) } -func parseNegative(code UNPARSEcode, index int, codeline []UNPARSEcode) (negative, bool, ArErr, int) { +func parseNegative(code UNPARSEcode, index int, codeline []UNPARSEcode) (any, bool, ArErr, int) { + trimmed := strings.TrimSpace(code.code) + trimmednegative := strings.TrimLeft(trimmed, "-") + difference := len(trimmed) - len(trimmednegative) resp, worked, err, i := translateVal(UNPARSEcode{ - code: strings.TrimSpace(code.code)[1:], + code: trimmednegative, realcode: code.realcode, line: code.line, path: code.path, }, index, codeline, 0) + + if difference%2 == 0 { + return resp, worked, err, i + } return negative{ VAL: resp, line: code.line, diff --git a/src/operations.go b/src/operations.go index dac4c96..79153f6 100644 --- a/src/operations.go +++ b/src/operations.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "reflect" + "strings" ) var operations = [][]string{ @@ -50,7 +51,8 @@ var one = newNumber().SetInt64(1) type operationType struct { operation int - values []any + value1 any + value2 any line int code string path string @@ -58,67 +60,60 @@ type operationType struct { func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (operationType, bool, ArErr, int) { for i := 0; i < len(operations); i++ { - values := []any{} - current := 0 - totalindex := 1 - for l := 0; l < len(code.code); l++ { - for j := 0; j < len(operations[i]); j++ { - if len(code.code[l:]) >= len(operations[i][j]) && code.code[l:l+len(operations[i][j])] == operations[i][j] { - - resp, success, _, respindex := translateVal( - UNPARSEcode{ - code: code.code[current:l], - realcode: code.realcode, - line: code.line, - path: code.path, - }, index, codelines, 0) - - if success { - totalindex += respindex - 1 - values = append(values, resp) - current = l + len(operations[i][j]) - } - } + for j := 0; j < len(operations[i]); j++ { + split := strings.Split(code.code, operations[i][j]) + if len(split) <= 1 { + continue } - } - if len(values) > 0 { - resp, success, err, respindex := translateVal( - UNPARSEcode{ - code: code.code[current:], + 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, line: code.line, path: code.path, }, index, codelines, 0) - if success { - totalindex += respindex - 1 - values = append(values, resp) + if !worked || err.EXISTS { + if k == len(split)-1 { + return operationType{}, false, err, 0 + } else { + continue + } + } + + val2, worked, err, step2 := translateVal(UNPARSEcode{ + code: strings.Join(split[k+1:], operations[i][j]), + realcode: code.realcode, + line: code.line, + path: code.path, + }, index, codelines, 0) + if !worked || err.EXISTS { + if k == len(split)-1 { + return operationType{}, false, err, 0 + } else { + continue + } + } return operationType{ i, - values, + val1, + val2, code.line, - code.realcode, + code.code, code.path, - }, true, err, totalindex + }, true, ArErr{}, step1 + step2 - 1 + } - return operationType{}, false, err, totalindex } } return operationType{}, false, ArErr{}, 0 } func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { - if len(o.values) != 2 { - return false, ArErr{ - "Runtime Error", - "Invalid number of values for comparison", - o.line, - o.path, - o.code, - true, - } - } resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -127,7 +122,7 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { } resp2, err := runVal( - o.values[1], + o.value2, stack, stacklevel+1, ) @@ -261,7 +256,7 @@ func compareValues(o operationType, stack stack, stacklevel int) (bool, ArErr) { func calcNegative(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -272,52 +267,46 @@ func calcNegative(o operationType, stack stack, stacklevel int) (any, ArErr) { 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, - ) - if err.EXISTS { - return nil, err - } - 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, - } - + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err + } + if typeof(output) == "number" && typeof(resp) == "number" { + return output.(number).Sub(output.(number), resp.(number)), ArErr{} + } 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 + } + return val, ArErr{} + } + } + 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) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -328,52 +317,49 @@ func calcDivide(o operationType, stack stack, stacklevel int) (any, ArErr) { 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["__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 + resp, err = runVal( + o.value2, + 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)) + return output, ArErr{} + } 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 } - } - return nil, ArErr{ - "Runtime Error", - "Cannot divide type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + output = val + return output, ArErr{} } } - return output, ArErr{} + return nil, ArErr{ + "Runtime Error", + "Cannot divide type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -384,51 +370,64 @@ func calcAdd(o operationType, stack stack, stacklevel int) (any, ArErr) { if typeof(output) == "number" { output = newNumber().Set(output.(number)) } - for i := 1; i < len(o.values); i++ { - resp, err := runVal( - o.values[i], - stack, - stacklevel+1, - ) - if err.EXISTS { - return nil, err - } - if typeof(output) == "number" && typeof(resp) == "number" { - output = output.(number).Add(output.(number), resp.(number)) - 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 - } + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err + } + if typeof(output) == "number" && typeof(resp) == "number" { + output = output.(number).Add(output.(number), resp.(number)) + return output, ArErr{} + } 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 { output = val - continue + return output, ArErr{} } } - return nil, ArErr{ - "Runtime Error", - "Cannot add type '" + typeof(resp) + "' to type '" + typeof(output) + "'", - o.line, - o.path, - o.code, - true, + } + if x, ok := resp.(ArObject); ok { + if y, ok := x.obj["__PostAdd__"]; ok { + val, err := runCall( + call{ + y, + []any{output}, + o.code, + o.line, + o.path, + }, stack, stacklevel+1) + if !err.EXISTS { + output = val + return output, ArErr{} + } } } - return (output), ArErr{} + + return nil, ArErr{ + "Runtime Error", + "Cannot add type '" + typeof(resp) + "' to type '" + typeof(output) + "'", + o.line, + o.path, + o.code, + true, + } } func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -439,88 +438,100 @@ func calcMul(o operationType, stack stack, stacklevel int) (any, ArErr) { 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, - ) - if err.EXISTS { - return nil, err - } - if typeof(output) == "number" && typeof(resp) == "number" { - output = output.(number).Mul(output.(number), resp.(number)) - 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, - } - + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err + } + if typeof(output) == "number" && typeof(resp) == "number" { + output = output.(number).Mul(output.(number), resp.(number)) + return output, ArErr{} + } 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 + return output, ArErr{} + } + } + return nil, ArErr{ + "Runtime Error", + "Cannot multiply type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, } - return output, ArErr{} } func calcAnd(o operationType, stack stack, stacklevel int) (any, ArErr) { - var output any = false - for i := 0; i < len(o.values); i++ { - resp, err := runVal( - o.values[i], - stack, - stacklevel+1, - ) - resp = ArValidToAny(resp) - if err.EXISTS { - return nil, err - } - if !anyToBool(resp) { - return resp, ArErr{} - } - output = resp + resp, err := runVal( + o.value1, + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err } - return output, ArErr{} + if !anyToBool(resp) { + return resp, ArErr{} + } + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + if err.EXISTS { + return nil, err + } + if !anyToBool(resp) { + return resp, ArErr{} + } + return resp, ArErr{} } func calcOr(o operationType, stack stack, stacklevel int) (any, ArErr) { - var output any = false - for i := 0; i < len(o.values); i++ { - resp, err := runVal( - o.values[i], - stack, - stacklevel+1, - ) - resp = ArValidToAny(resp) - if err.EXISTS { - return nil, err - } - if anyToBool(resp) { - return resp, ArErr{} - } - output = resp + resp, err := runVal( + o.value1, + stack, + stacklevel+1, + ) + resp = ArValidToAny(resp) + if err.EXISTS { + return nil, err } - return output, ArErr{} + if anyToBool(resp) { + return resp, ArErr{} + } + resp, err = runVal( + o.value1, + stack, + stacklevel+1, + ) + resp = ArValidToAny(resp) + if err.EXISTS { + return nil, err + } + if anyToBool(resp) { + return resp, ArErr{} + } + return resp, ArErr{} } +// InSlice checks if an element is present in a slice of any type. +// It returns true if the element is found, false otherwise. func InSlice(a any, list []any) bool { for _, b := range list { if b == a { @@ -529,41 +540,35 @@ func InSlice(a any, list []any) bool { } return false } + +// calcNotIn is a function that calculates the 'not in' operation between two values. +// It takes in an operationType 'o', a stack 'stack', and a stack level 'stacklevel'. +// It returns an 'any' value and an 'ArErr' error. +// The 'o' parameter contains information about the operation to be performed, including the values to be compared, the line of code, and the file path. func calcNotIn(o operationType, stack stack, stacklevel int) (any, ArErr) { - if len(o.values) != 2 { - return false, ArErr{ - "Runtime Error", - "Invalid number of arguments for 'not in'", - o.line, - o.path, - o.code, - true, - } - } resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) - resp = ArValidToAny(resp) if err.EXISTS { return false, err } resp2, err := runVal( - o.values[1], + o.value2, stack, stacklevel+1, ) if err.EXISTS { return false, err } - if x, ok := resp.(ArObject); ok { + if x, ok := resp2.(ArObject); ok { if y, ok := x.obj["__NotContains__"]; ok { return runCall( call{ y, - []any{resp2}, + []any{resp}, o.code, o.line, o.path, @@ -580,19 +585,13 @@ func calcNotIn(o operationType, stack stack, stacklevel int) (any, ArErr) { } } +// calcIn is a function that calculates the 'in' operation between two values. +// It takes in an operationType 'o', a stack 'stack', and a stack level 'stacklevel'. +// It returns an 'any' value and an 'ArErr' error. +// The 'o' parameter contains information about the operation to be performed, including the values to be compared, the line of code, and the file path. func calcIn(o operationType, stack stack, stacklevel int) (any, ArErr) { - if len(o.values) != 2 { - return false, ArErr{ - "Runtime Error", - "Invalid number of arguments for 'not in'", - o.line, - o.path, - o.code, - true, - } - } resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -601,7 +600,7 @@ func calcIn(o operationType, stack stack, stacklevel int) (any, ArErr) { } resp2, err := runVal( - o.values[1], + o.value2, stack, stacklevel+1, ) @@ -676,7 +675,7 @@ func equals(a any, b any, o operationType, stack stack, stacklevel int) (bool, A func calcMod(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -687,55 +686,52 @@ func calcMod(o operationType, stack stack, stacklevel int) (any, ArErr) { 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" { - x := newNumber().Set(resp.(number)) - x.Quo(output.(number), x) - x = floor(x) - x.Mul(x, resp.(number)) - output.(number).Sub(output.(number), x) - 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 + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + resp = ArValidToAny(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) == "number" && typeof(output) == "number" { + x := newNumber().Set(resp.(number)) + x.Quo(output.(number), x) + x = floor(x) + x.Mul(x, resp.(number)) + output.(number).Sub(output.(number), x) + return output, ArErr{} + } 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 } - } - return nil, ArErr{ - "Runtime Error", - "Cannot calculate modulus of type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + output = val + return output, ArErr{} } } - return output, ArErr{} + return nil, ArErr{ + "Runtime Error", + "Cannot calculate modulus of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } func calcIntDiv(o operationType, stack stack, stacklevel int) (any, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -746,51 +742,48 @@ func calcIntDiv(o operationType, stack stack, stacklevel int) (any, ArErr) { 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 + resp, err = runVal( + o.value2, + 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)) + return output, ArErr{} + } 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 } - } - return nil, ArErr{ - "Runtime Error", - "Cannot divide type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + output = val + return output, ArErr{} } } - return output, ArErr{} + return nil, ArErr{ + "Runtime Error", + "Cannot divide type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } } func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { resp, err := runVal( - o.values[0], + o.value1, stack, stacklevel+1, ) @@ -809,69 +802,67 @@ func calcPower(o operationType, stack stack, stacklevel int) (number, ArErr) { } } 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" { - n := newNumber().Set(resp.(number)) - if n.Cmp(newNumber().SetInt64(10)) <= 0 { - toOut := newNumber().SetInt64(1) - clone := newNumber().Set(output) - nAbs := (abs(newNumber().Set(n))) - j := newNumber() - for ; j.Cmp(nAbs) < 0; j.Add(j, one) { - toOut.Mul(toOut, clone) - } + resp, err = runVal( + o.value2, + stack, + stacklevel+1, + ) + resp = ArValidToAny(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) == "number" { + n := newNumber().Set(resp.(number)) + if n.Cmp(newNumber().SetInt64(10)) <= 0 { + toOut := newNumber().SetInt64(1) + clone := newNumber().Set(output) + nAbs := (abs(newNumber().Set(n))) + j := newNumber() + for ; j.Cmp(nAbs) < 0; j.Add(j, one) { + toOut.Mul(toOut, clone) + } - nAbs.Sub(nAbs, j) - if nAbs.Cmp(newNumber()) < 0 { - j.Sub(j, one) - n1, _ := toOut.Float64() - n2, _ := nAbs.Float64() - calculated := newNumber().SetFloat64(math.Pow(n1, n2)) - if calculated == nil { - calculated = infinity - } - toOut.Mul(toOut, calculated) - } - if n.Cmp(newNumber()) < 0 { - toOut.Quo(newNumber().SetInt64(1), toOut) - } - output.Set(toOut) - } else if n.Cmp(newNumber().SetInt64(1)) != 0 { - n1, _ := output.Float64() - n2, _ := n.Float64() + nAbs.Sub(nAbs, j) + if nAbs.Cmp(newNumber()) < 0 { + j.Sub(j, one) + n1, _ := toOut.Float64() + n2, _ := nAbs.Float64() calculated := newNumber().SetFloat64(math.Pow(n1, n2)) if calculated == nil { calculated = infinity } - output.Mul(output, calculated) + toOut.Mul(toOut, calculated) } + if n.Cmp(newNumber()) < 0 { + toOut.Quo(newNumber().SetInt64(1), toOut) + } + output.Set(toOut) + } else if n.Cmp(newNumber().SetInt64(1)) != 0 { + n1, _ := output.Float64() + n2, _ := n.Float64() + calculated := newNumber().SetFloat64(math.Pow(n1, n2)) + if calculated == nil { + calculated = infinity + } + output.Mul(output, calculated) + } - /* - n1, _ := output.Float64() - n2, _ := resp.(number).Float64() - output = newNumber().SetFloat64(math.Pow(n1, n2)) - if output == nil { - output = infinity - } - */ - } else { - return nil, ArErr{ - "Runtime Error", - "Cannot calculate power of type '" + typeof(resp) + "'", - o.line, - o.path, - o.code, - true, + /* + n1, _ := output.Float64() + n2, _ := resp.(number).Float64() + output = newNumber().SetFloat64(math.Pow(n1, n2)) + if output == nil { + output = infinity } + */ + } else { + return nil, ArErr{ + "Runtime Error", + "Cannot calculate power of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, } } return output, ArErr{} diff --git a/src/string.go b/src/string.go index 7b67ba6..e6c173b 100644 --- a/src/string.go +++ b/src/string.go @@ -567,6 +567,18 @@ func ArString(str string) ArObject { } return strings.Join([]string{str, a[0].(string)}, ""), ArErr{} }} + obj.obj["__PostAdd__"] = builtinFunc{ + "__PostAdd__", + func(a ...any) (any, ArErr) { + if len(a) != 1 { + return nil, ArErr{"TypeError", "expected 1 argument, got " + fmt.Sprint(len(a)), 0, "", "", true} + } + a[0] = ArValidToAny(a[0]) + if typeof(a[0]) != "string" { + a[0] = anyToArgon(a[0], false, false, 3, 0, false, 0) + } + return strings.Join([]string{a[0].(string), str}, ""), ArErr{} + }} obj.obj["__Multiply__"] = builtinFunc{ "__Multiply__", func(a ...any) (any, ArErr) { diff --git a/src/term-class.go b/src/term-class.go index f61f784..d7ede5a 100644 --- a/src/term-class.go +++ b/src/term-class.go @@ -131,11 +131,12 @@ var ArInput = Map( } return ArString(resp), ArErr{} }}, + "__call__": builtinFunc{"input", func(args ...any) (any, ArErr) { + return input(args...), ArErr{} + }}, + "pause": builtinFunc{"pause", func(args ...any) (any, ArErr) { + pause() + return nil, ArErr{} + }}, }, ) - -func init() { - ArInput.obj["__call__"] = builtinFunc{"input", func(args ...any) (any, ArErr) { - return input(args...), ArErr{} - }} -} diff --git a/src/translate.go b/src/translate.go index ecc9dcf..89c3ab9 100644 --- a/src/translate.go +++ b/src/translate.go @@ -151,6 +151,7 @@ func translate(codelines []UNPARSEcode) ([]any, ArErr) { if err.EXISTS { return nil, err } + translated = append(translated, val) } return translated, ArErr{} diff --git a/test.ar b/test.ar deleted file mode 100644 index 3f3085d..0000000 --- a/test.ar +++ /dev/null @@ -1 +0,0 @@ -term.log(null) \ No newline at end of file diff --git a/testingoop.py b/testingoop.py new file mode 100644 index 0000000..20617f0 --- /dev/null +++ b/testingoop.py @@ -0,0 +1,21 @@ +class obj1: + def __init__(self) -> None: + pass + + def __add__(self, other): + print("obj1") + return 10 + +class obj2: + def __init__(self) -> None: + pass + + def __add__(self, other): + print("obj2") + return 20 + +obj1 = obj1() +obj2 = obj2() + +print(obj1 + obj2) +print(obj2 + obj1) \ No newline at end of file diff --git a/tests/brainfuck.ar b/tests/brainfuck.ar index 3568287..6996a58 100644 --- a/tests/brainfuck.ar +++ b/tests/brainfuck.ar @@ -15,7 +15,7 @@ let interpret(code) = do else if (command == '-') do if (pointer not in memory) memory[pointer] = 0 memory[pointer] = memory[pointer] - 1 - else if (command == '.') term.plain.oneLine(chr(memory.get(pointer, 0)), end='') + else if (command == '.') term.log((memory.get(pointer, 0))) else if (command == ',') memory[pointer] = ord(input()) else if (command == '[') do if (memory.get(pointer, 0) == 0) do @@ -30,5 +30,5 @@ let interpret(code) = do else loops.pop() code_ptr = code_ptr + 1 - -interpret('>++++++++[<+++++++++>-]<.>++++[<+++++++>-]<+.+++++++..+++.>>++++++[<+++++++>-]<++.------------.>++++++[<+++++++++>-]<+.<.+++.------.--------.>>>++++[<++++++++>-]<+.') \ No newline at end of file +term.log("hello worldf") +interpret('>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.>++++++++++.') \ No newline at end of file diff --git a/tests/csv_test.ar b/tests/csv_test.ar index 5da29fe..9b71673 100644 --- a/tests/csv_test.ar +++ b/tests/csv_test.ar @@ -2,4 +2,4 @@ import "csv" as csv let table = (csv.read("tests/test.csv")) -term.log(number(table[::-1][0][::-1][0])) \ No newline at end of file +term.log(table) \ No newline at end of file diff --git a/tests/diff.ar b/tests/diff.ar index fe0c42e..4492f49 100644 --- a/tests/diff.ar +++ b/tests/diff.ar @@ -1,19 +1,15 @@ -let zero = 1/infinity +let zero = 1e-1000 let diff(f) = (x) = (f(x + zero) - f(x)) / zero -let count = 0 let f(x) = do - count = count + 1 - term.log(count) return x^10+x^9+x^8+x^7+x^6+x^5+x^4+x^3+x^2+x+1 -x = 100 -d = 0 +let x = 100 +let d = 0 forever do - n = f(x) + let n = f(x) term.log("f"+("'"*d)+"("+x+") = "+n) if (n == 0) break f = diff(f) - d = d + 1 - count = 0 \ No newline at end of file + d = d + 1 \ No newline at end of file diff --git a/tests/memoryLeakTest.ar b/tests/memoryLeakTest.ar index 74660ee..6be1570 100644 --- a/tests/memoryLeakTest.ar +++ b/tests/memoryLeakTest.ar @@ -1,7 +1,8 @@ f() = do - a = [] - for (i from 0 to 100000) a.append(i) + let a = [] + for (i from 0 to 10000000) a.append(i) term.log("start") f() -term.log("end") \ No newline at end of file +term.log("end") +input() \ No newline at end of file diff --git a/tests/welcomemessage.ar b/tests/welcomemessage.ar deleted file mode 100644 index 727813b..0000000 --- a/tests/welcomemessage.ar +++ /dev/null @@ -1,9 +0,0 @@ -term.log(" /\\ |___ \\ ") -term.log(" / \\ _ __ __ _ ___ _ __ __ ____) |") -term.log(" / /\\ \\ | '__/ _` |/ _ \\| '_ \\ \\ \\ / /__ < ") -term.log(" / ____ \\| | | (_| | (_) | | | | \\ V /___) |") -term.log(" /_/ \\_\\_| \\__, |\\___/|_| |_| \\_/|____/ ") -term.log(" __/ | ") -term.log(" |___/ ") -term.log("----------------------------------------------") -term.log("Welcome to ARGON!") \ No newline at end of file