diff --git a/src/callable.go b/src/callable.go index 66bd627..7076abe 100644 --- a/src/callable.go +++ b/src/callable.go @@ -1,7 +1,6 @@ package main type Callable struct { - name string params []string run any code string diff --git a/src/import.go b/src/import.go index ca739ad..05145f6 100644 --- a/src/import.go +++ b/src/import.go @@ -99,7 +99,7 @@ func importMod(realpath string, origin string, main bool) ArErr { return translationerr } global := scope{} - _, runimeErr, _, _ := run(translated, stack{vars, global}) + _, runimeErr, _ := run(translated, stack{vars, global}) if runimeErr.EXISTS { return runimeErr } diff --git a/src/run.go b/src/run.go index ee2ad80..033fa7c 100644 --- a/src/run.go +++ b/src/run.go @@ -54,15 +54,14 @@ func runVal(line any, stack stack) (any, ArErr) { } // returns error -func run(translated []any, stack stack) (any, ArErr, int, any) { +func run(translated []any, stack stack) (any, ArErr, any) { var output any = nil - count := 0 for _, val := range translated { val, err := runVal(val, stack) output = val if err.EXISTS { - return nil, err, count, output + return nil, err, output } } - return nil, ArErr{}, count, output + return nil, ArErr{}, output } diff --git a/src/shell.go b/src/shell.go index a753c8c..0be6383 100644 --- a/src/shell.go +++ b/src/shell.go @@ -22,14 +22,15 @@ func shell() { code := input("\x1b[38;5;240m>>> \x1b[0m\x1b[1;5;240m") fmt.Print("\x1b[0m") translated, translationerr := translate([]UNPARSEcode{{code, code, 1, ""}}) + count := len(translated) if translationerr.EXISTS { panicErr(translationerr) } - _, runimeErr, count, output := run(translated, global) + _, runimeErr, output := run(translated, global) if runimeErr.EXISTS { panicErr(runimeErr) } - if count == 0 { + if count == 1 { fmt.Println(anyToArgon(output, true, true, 3, 0, true, 1)) } } diff --git a/src/to-argon.go b/src/to-argon.go index c4eb79d..f908eb3 100644 --- a/src/to-argon.go +++ b/src/to-argon.go @@ -94,7 +94,7 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, color b if color { output = append(output, "\x1b[38;5;240m") } - output = append(output, "") + output = append(output, "") if color { output = append(output, "\x1b[0m") } diff --git a/src/translate.go b/src/translate.go index 41b6b7d..0bc3c81 100644 --- a/src/translate.go +++ b/src/translate.go @@ -26,12 +26,19 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b if worked { return bracket, worked, err, step } - } else if isSetVariable(code) { + } + if isSetVariable(code) { setvar, worked, err, step := parseSetVariable(code, index, codelines) if worked { return setvar, worked, err, step } } + if isAutoAsignVariable(code) { + setvar, worked, err, step := parseAutoAsignVariable(code, index, codelines) + if worked { + return setvar, worked, err, step + } + } operation, worked, err, step := parseOperations(code, index, codelines) if worked { return operation, worked, err, step diff --git a/src/typeof.go b/src/typeof.go index f4a299e..8751ac6 100644 --- a/src/typeof.go +++ b/src/typeof.go @@ -16,6 +16,8 @@ func typeof(val any) string { return "function" case ArMap: return "map" + case accessVariable: + return "variable" } return "unknown" } diff --git a/src/variable.go b/src/variable.go index 62d81f3..9c968f4 100644 --- a/src/variable.go +++ b/src/variable.go @@ -1,11 +1,15 @@ package main import ( + "fmt" "strings" ) var variableCompile = makeRegex(`( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`) -var setVariableCompile = makeRegex(`( *)(let( +))?([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*(\(( *)((([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)(( *)\,( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)*)?( *)\))?( *)=(.|\n)+`) +var validname = makeRegex(`(.|\n)+(\(( *)((([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)(( *)\,( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)*)?( *)\))`) +var setVariableCompile = makeRegex(`( *)(let( +))(.|\n)+( *)=(.|\n)+`) +var autoAsignVariableCompile = makeRegex(`(.|\n)+=(.|\n)+`) +var deleteVariableCompile = makeRegex(`( *)delete( +)( *)`) var blockedVariableNames = map[string]bool{ "if": true, @@ -20,6 +24,10 @@ var blockedVariableNames = map[string]bool{ "import": true, "from": true, "do": true, + "true": true, + "false": true, + "null": true, + "delete": true, } type accessVariable struct { @@ -31,7 +39,7 @@ type accessVariable struct { type setVariable struct { TYPE string - name string + toset any value any function bool params []string @@ -40,15 +48,17 @@ type setVariable struct { path string } +type setFunction struct { + toset any + params []string +} + func isVariable(code UNPARSEcode) bool { return variableCompile.MatchString(code.code) } func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) { name := strings.TrimSpace(code.code) - if blockedVariableNames[name] { - return accessVariable{}, false, ArErr{"Naming Error", "Naming Error: \"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 - } return accessVariable{name: name, code: code.code, line: code.line, path: code.path}, true, ArErr{}, 1 } @@ -65,41 +75,106 @@ func isSetVariable(code UNPARSEcode) bool { return setVariableCompile.MatchString(code.code) } +func isAutoAsignVariable(code UNPARSEcode) bool { + return autoAsignVariableCompile.MatchString(code.code) +} + +func isDeleteVariable(code UNPARSEcode) bool { + return deleteVariableCompile.MatchString(code.code) +} + +func nameToTranslated(code UNPARSEcode, index int, lines []UNPARSEcode) (any, bool, ArErr, int) { + if validname.MatchString(code.code) { + trimmed := strings.TrimSpace(code.code) + start := strings.LastIndex(trimmed, "(") + params := strings.Split(trimmed[start+1:len(trimmed)-1], ",") + for i := range params { + params[i] = strings.TrimSpace(params[i]) + } + name := strings.TrimSpace(trimmed[:start]) + fmt.Println(name) + if blockedVariableNames[name] { + fmt.Println(name) + return accessVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 + } + value, success, err, i := translateVal(UNPARSEcode{ + code: name, + realcode: code.realcode, + line: code.line, + path: code.path, + }, index, lines, false) + return setFunction{toset: value, params: params}, success, err, i + } + return translateVal(code, index, lines, false) +} + func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { trim := strings.TrimSpace(code.code) equalsplit := strings.SplitN(trim, "=", 2) spacesplit := strings.SplitN(equalsplit[0], " ", 2) - TYPE := "auto" - name := strings.TrimSpace(equalsplit[0]) + name := strings.TrimSpace(spacesplit[1]) params := []string{} function := false - if spacesplit[0] == "let" { - TYPE = "let" - name = strings.TrimSpace(spacesplit[1]) - } - if name[len(name)-1] == ')' { - function = true - bracketsplit := strings.SplitN(name, "(", 2) - name = bracketsplit[0] - params = strings.Split(bracketsplit[1][:len(bracketsplit[1])-1], ",") - for i := 0; i < len(params); i++ { - params[i] = strings.TrimSpace(params[i]) - } - } if blockedVariableNames[name] { - return setVariable{}, false, ArErr{"Naming Error", "Naming Error: \"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 + return setVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 } - value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, true) + toset, success, err, i := nameToTranslated(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines) + if err.EXISTS { + return setVariable{}, success, err, i + } + switch toset.(type) { + case accessVariable: + break + case setFunction: + function = true + params = toset.(setFunction).params + toset = toset.(setFunction).toset + default: + return setVariable{}, false, ArErr{"Type Error", "can't set for non variable, did you mean '=='?", code.line, code.path, code.realcode, true}, 1 + } + value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, false) if !success { return setVariable{}, false, err, i } - return setVariable{TYPE: TYPE, name: name, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i + return setVariable{TYPE: "let", toset: toset, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i +} + +func parseAutoAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { + trim := strings.TrimSpace(code.code) + equalsplit := strings.SplitN(trim, "=", 2) + name := strings.TrimSpace(equalsplit[0]) + params := []string{} + function := false + if blockedVariableNames[name] { + return setVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 + } + toset, success, err, i := nameToTranslated(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines) + if err.EXISTS { + return setVariable{}, success, err, i + } + switch toset.(type) { + case accessVariable: + break + case ArMapGet: + break + case setFunction: + function = true + params = toset.(setFunction).params + toset = toset.(setFunction).toset + default: + return setVariable{}, false, ArErr{"Type Error", "can't set for non variable, did you mean '=='?", code.line, code.path, code.realcode, true}, 1 + } + value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, false) + if !success { + return setVariable{}, false, err, i + } + return setVariable{TYPE: "auto", toset: toset, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i } func setVariableValue(v setVariable, stack stack) (any, ArErr) { var resp any if v.function { - resp = Callable{v.name, v.params, v.value, v.code, stack, v.line} + resp = Callable{v.params, v.value, v.code, stack, v.line} } else { respp, err := runVal(v.value, stack) if err.EXISTS { @@ -107,19 +182,60 @@ func setVariableValue(v setVariable, stack stack) (any, ArErr) { } resp = respp } + if v.TYPE == "let" { - if _, ok := stack[len(stack)-1][v.name]; ok { - return stack, ArErr{"Runtime Error", "variable \"" + v.name + "\" already exists", v.line, v.path, v.code, true} + if _, ok := stack[len(stack)-1][v.toset.(accessVariable).name]; ok { + return stack, ArErr{"Runtime Error", "variable \"" + v.toset.(accessVariable).name + "\" already exists", v.line, v.path, v.code, true} } - stack[len(stack)-1][v.name] = resp + stack[len(stack)-1][v.toset.(accessVariable).name] = resp } else { - for i := len(stack) - 1; i >= 0; i-- { - if _, ok := stack[i][v.name]; ok { - stack[i][v.name] = resp - return resp, ArErr{} + switch x := v.toset.(type) { + case accessVariable: + for i := len(stack) - 1; i >= 0; i-- { + if _, ok := stack[i][x.name]; ok { + stack[i][x.name] = resp + return resp, ArErr{} + } + } + stack[len(stack)-1][x.name] = resp + case ArMapGet: + respp, err := runVal(x.VAL, stack) + if err.EXISTS { + return nil, err + } + key, err := runVal(x.key, stack) + if err.EXISTS { + return nil, err + } + switch y := respp.(type) { + case ArMap: + y[key] = resp + default: + return nil, ArErr{"Runtime Error", "can't set for non map", v.line, v.path, v.code, true} } } - stack[len(stack)-1][v.name] = resp } return resp, ArErr{} } + +/* + +func parseAutosAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { + trim := strings.TrimSpace(code.code) + equalsplit := strings.SplitN(trim, "=", 2) + name := strings.TrimSpace(equalsplit[0]) + params := []string{} + function := false + + if blockedVariableNames[name] { + return setVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 + } + value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, false) + if !success { + return setVariable{}, false, err, i + } + return setVariable{TYPE: "let", name: name, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i +} + + +*/