diff --git a/src/brackets.go b/src/brackets.go index 2ab9d6c..3a59e09 100644 --- a/src/brackets.go +++ b/src/brackets.go @@ -24,7 +24,7 @@ func parseBrackets(code UNPARSEcode, index int, codeline []UNPARSEcode) (bracket realcode: code.realcode, line: code.line, path: code.path, - }, index, codeline, false) + }, index, codeline, 0) return brackets{ VAL: resp, line: code.line, diff --git a/src/built-ins.go b/src/built-ins.go index c68356a..bbf4f18 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -1,7 +1,5 @@ package main -import "github.com/wadey/go-rounding" - var vars = scope{} func init() { @@ -67,35 +65,10 @@ func init() { } return nil, ArErr{TYPE: "TypeError", message: "Cannot create array from '" + typeof(a[0]) + "'", EXISTS: true} }} - vars["round"] = builtinFunc{"round", func(a ...any) (any, ArErr) { - if len(a) == 0 { - return nil, ArErr{TYPE: "round", message: "round takes 1 argument", - EXISTS: true} - } - precision := newNumber() - if len(a) > 1 { - switch x := a[1].(type) { - case number: - if !x.IsInt() { - return nil, ArErr{TYPE: "TypeError", message: "Cannot round to '" + typeof(a[1]) + "'", EXISTS: true} - } - precision = x - default: - return nil, ArErr{TYPE: "TypeError", message: "Cannot round to '" + typeof(a[1]) + "'", EXISTS: true} - } - } - - switch x := a[0].(type) { - case number: - return rounding.Round(newNumber().Set(x), int(precision.Num().Int64()), rounding.HalfUp), ArErr{} - } - return nil, ArErr{TYPE: "TypeError", message: "Cannot round '" + typeof(a[0]) + "'", EXISTS: true} - }} + vars["maths"] = maths vars["time"] = ArTime vars["PI"] = PI vars["π"] = PI vars["e"] = e - sqrt := builtinFunc{"sqrt", ArgonSqrt} - vars["sqrt"] = sqrt vars["thread"] = builtinFunc{"thread", ArThread} } diff --git a/src/call.go b/src/call.go index be008d8..1fea684 100644 --- a/src/call.go +++ b/src/call.go @@ -38,7 +38,7 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, } continue } - resp, worked, _, _ := translateVal(UNPARSEcode{code: name, realcode: code.realcode, line: index + 1, path: code.path}, index, codelines, false) + resp, worked, _, _ := translateVal(UNPARSEcode{code: name, realcode: code.realcode, line: index + 1, path: code.path}, index, codelines, 0) if !worked { if i == len(splitby)-1 { return nil, false, ArErr{"Syntax Error", "invalid callable", code.line, code.path, code.realcode, true}, 1 @@ -94,6 +94,10 @@ func runCall(c call, stack stack) (any, ArErr) { level[param] = args[i] } resp, err := runVal(x.run, append(x.stack, level)) + switch x := resp.(type) { + case PassBackJumpStatment: + resp = x.value + } return resp, err } return nil, ArErr{"Runtime Error", "type '" + typeof(callable) + "' is not callable", c.line, c.path, c.code, true} diff --git a/src/comment.go b/src/comment.go index 88ea77d..8dd2551 100644 --- a/src/comment.go +++ b/src/comment.go @@ -21,7 +21,7 @@ func parseComment(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bo for i := 0; i < len(split)-1; i++ { temp = append(temp, split[i]) joined := strings.Join(temp, "#") - resp, worked, _, s := translateVal(UNPARSEcode{code: joined, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, true) + resp, worked, _, s := translateVal(UNPARSEcode{code: joined, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, 0) step += s - 1 if worked { return resp, true, ArErr{}, step diff --git a/src/dowraps.go b/src/dowraps.go new file mode 100644 index 0000000..907b140 --- /dev/null +++ b/src/dowraps.go @@ -0,0 +1,64 @@ +package main + +import ( + "strings" +) + +var dowrapCompile = makeRegex("( )*do( )*") + +type dowrap struct { + run []any + line int + path string + code string +} + +func isDoWrap(code UNPARSEcode) bool { + return dowrapCompile.MatchString(code.code) +} + +func parseDoWrap(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { + currentindent := len(code.code) - len(strings.TrimLeft(code.code, " ")) + var setindent int = -1 + var i = index + 1 + translated := []any{} + for i < len(codelines) { + if isBlank(codelines[i]) { + i++ + continue + } + indent := len(codelines[i].code) - len(strings.TrimLeft(codelines[i].code, " ")) + if setindent == -1 { + setindent = indent + } + if indent <= currentindent { + break + } + if indent != setindent { + return nil, false, ArErr{"Syntax Error", "invalid indent", code.line, code.path, code.realcode, true}, 1 + } + + val, _, err, step := translateVal(codelines[i], i, codelines, 2) + i += step + if err.EXISTS { + return nil, false, err, i - index + } + translated = append(translated, val) + } + return dowrap{run: translated, line: code.line, path: code.path, code: code.realcode}, true, ArErr{}, i - index +} + +func runDoWrap(d dowrap, stack stack) (any, ArErr) { + newstack := append(stack, scope{}) + for _, v := range d.run { + val, err := runVal(v, newstack) + if err.EXISTS { + return nil, err + } + switch x := val.(type) { + case PassBackJumpStatment: + return x, ArErr{} + } + } + return nil, ArErr{} +} diff --git a/src/factorial.go b/src/factorial.go index e77c0b5..d425aa4 100644 --- a/src/factorial.go +++ b/src/factorial.go @@ -16,7 +16,7 @@ type factorial struct { func parseFactorial(code UNPARSEcode, index int, codeline []UNPARSEcode) (factorial, bool, ArErr, int) { trim := strings.TrimSpace(code.code) trim = trim[:len(trim)-1] - val, success, err, i := translateVal(UNPARSEcode{code: trim, realcode: code.realcode, line: 1, path: ""}, 0, []UNPARSEcode{}, false) + val, success, err, i := translateVal(UNPARSEcode{code: trim, realcode: code.realcode, line: 1, path: ""}, 0, []UNPARSEcode{}, 0) if !success { return factorial{}, false, err, i } diff --git a/src/jumpStatments.go b/src/jumpStatments.go new file mode 100644 index 0000000..6467ffa --- /dev/null +++ b/src/jumpStatments.go @@ -0,0 +1,59 @@ +package main + +import "strings" + +var returnCompile = makeRegex(`( *)return( +)(.|\n)+`) + +type CallJumpStatment struct { + TYPE string + value any + line int + code string + path string +} + +type PassBackJumpStatment struct { + TYPE string + value any + line int + code string + path string +} + +func isReturn(code UNPARSEcode) bool { + return returnCompile.MatchString(code.code) +} + +func parseReturn(code UNPARSEcode, index int, codeline []UNPARSEcode) (CallJumpStatment, bool, ArErr, int) { + resp, worked, err, i := translateVal(UNPARSEcode{ + code: strings.TrimSpace(code.code)[6:], + realcode: code.realcode, + line: code.line, + path: code.path, + }, index, codeline, 0) + return CallJumpStatment{ + TYPE: "return", + value: resp, + line: code.line, + code: code.realcode, + path: code.path, + }, worked, err, i +} + +func runJumpStatment(code CallJumpStatment, stack stack) (any, ArErr) { + var val any + if code.value != nil { + v, err := runVal(code.value, stack) + if err.EXISTS { + return nil, err + } + val = v + } + return PassBackJumpStatment{ + TYPE: code.TYPE, + value: val, + line: code.line, + code: code.code, + path: code.path, + }, ArErr{} +} diff --git a/src/letterseperateseperate.go b/src/letterseperateseperate.go index 5d1b925..6b5186f 100644 --- a/src/letterseperateseperate.go +++ b/src/letterseperateseperate.go @@ -18,7 +18,7 @@ func getValuesFromLetter(str string, splitstr string, index int, codelines []UNP arguments = append(arguments, nil) temp = []string{} } else { - resp, worked, _, _ := translateVal(UNPARSEcode{code: test, realcode: codelines[index].realcode, line: index + 1, path: codelines[index].path}, index, codelines, false) + resp, worked, _, _ := translateVal(UNPARSEcode{code: test, realcode: codelines[index].realcode, line: index + 1, path: codelines[index].path}, index, codelines, 0) if worked { arguments = append(arguments, resp) temp = []string{} diff --git a/src/mapAndArray.go b/src/mapAndArray.go index 244b46a..f1c2ce6 100644 --- a/src/mapAndArray.go +++ b/src/mapAndArray.go @@ -403,7 +403,7 @@ func mapGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapGet split := strings.Split(trim, ".") start := strings.Join(split[:len(split)-1], ".") key := split[len(split)-1] - resp, worked, err, i := translateVal(UNPARSEcode{code: start, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, false) + resp, worked, err, i := translateVal(UNPARSEcode{code: start, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, 0) if !worked { return ArMapGet{}, false, err, i } @@ -444,7 +444,7 @@ func indexGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapG true, }, 1 } - tival, worked, err, i := translateVal(UNPARSEcode{code: ti, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, false) + tival, worked, err, i := translateVal(UNPARSEcode{code: ti, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, 0) if !worked { if i == len(split)-1 { return ArMapGet{}, false, err, i diff --git a/src/negative.go b/src/negative.go index 9a2a06e..98a2257 100644 --- a/src/negative.go +++ b/src/negative.go @@ -21,7 +21,7 @@ func parseNegative(code UNPARSEcode, index int, codeline []UNPARSEcode) (negativ realcode: code.realcode, line: code.line, path: code.path, - }, index, codeline, false) + }, index, codeline, 0) return negative{ VAL: resp, line: code.line, diff --git a/src/operations.go b/src/operations.go index 830278b..ab998ed 100644 --- a/src/operations.go +++ b/src/operations.go @@ -70,7 +70,7 @@ func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (oper realcode: code.realcode, line: code.line, path: code.path, - }, index, codelines, false) + }, index, codelines, 0) if success { totalindex += respindex - 1 @@ -87,7 +87,7 @@ func parseOperations(code UNPARSEcode, index int, codelines []UNPARSEcode) (oper realcode: code.realcode, line: code.line, path: code.path, - }, index, codelines, false) + }, index, codelines, 0) if success { totalindex += respindex - 1 values = append(values, resp) diff --git a/src/run.go b/src/run.go index 4dbebdc..e67ed83 100644 --- a/src/run.go +++ b/src/run.go @@ -50,6 +50,10 @@ func runVal(line any, stack stack) (any, ArErr) { return runVal(x.VAL, stack) case operationType: return runOperation(x, stack) + case dowrap: + return runDoWrap(x, stack) + case CallJumpStatment: + return runJumpStatment(x, stack) case ArDelete: return runDelete(x, stack) } diff --git a/src/translate.go b/src/translate.go index fa3ad08..ecec099 100644 --- a/src/translate.go +++ b/src/translate.go @@ -1,5 +1,7 @@ package main +import "strings" + type UNPARSEcode struct { code string realcode string @@ -8,21 +10,31 @@ type UNPARSEcode struct { } // returns (number | string | nil), success, error, step -func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine bool) (any, bool, ArErr, int) { +func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine int) (any, bool, ArErr, int) { - if isLine { - if isBlank(code) { - return nil, true, ArErr{}, 1 - } else if isDeleteVariable(code) { + if isLine == 2 { + if isDeleteVariable(code) { return parseDelete(code, index, codelines) } else if isComment(code) { resp, worked, err, step := parseComment(code, index, codelines) if worked { return resp, worked, err, step } + } else if isReturn(code) { + return parseReturn(code, index, codelines) } } + if isLine >= 1 { + if isDoWrap(code) { + return parseDoWrap(code, index, codelines) + } + } + + if isLine == 2 { + isLine = 1 + } + if isBrackets(code) { bracket, worked, err, step := parseBrackets(code, index, codelines) if worked { @@ -30,13 +42,13 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b } } if isSetVariable(code) { - setvar, worked, err, step := parseSetVariable(code, index, codelines) + setvar, worked, err, step := parseSetVariable(code, index, codelines, isLine) if worked { return setvar, worked, err, step } } if isAutoAsignVariable(code) { - setvar, worked, err, step := parseAutoAsignVariable(code, index, codelines) + setvar, worked, err, step := parseAutoAsignVariable(code, index, codelines, isLine) if worked { return setvar, worked, err, step } @@ -75,14 +87,19 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b func translate(codelines []UNPARSEcode) ([]any, ArErr) { translated := []any{} for i := 0; i < len(codelines); { - val, _, err, step := translateVal(codelines[i], i, codelines, true) + if isBlank(codelines[i]) { + i++ + continue + } + currentindent := len(codelines[i].code) - len(strings.TrimLeft(codelines[i].code, " ")) + if currentindent != 0 { + return nil, ArErr{"Syntax Error", "invalid indent", codelines[i].line, codelines[i].path, codelines[i].realcode, true} + } + val, _, err, step := translateVal(codelines[i], i, codelines, 2) i += step if err.EXISTS { return nil, err } - if val == nil { - continue - } translated = append(translated, val) } return translated, ArErr{} diff --git a/src/variable.go b/src/variable.go index 2e26a90..07d6c74 100644 --- a/src/variable.go +++ b/src/variable.go @@ -65,7 +65,7 @@ func isVariable(code UNPARSEcode) bool { func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) { name := strings.TrimSpace(code.code) - return accessVariable{name: name, code: code.code, line: code.line, path: code.path}, true, ArErr{}, 1 + return accessVariable{name: name, code: code.realcode, line: code.line, path: code.path}, true, ArErr{}, 1 } func readVariable(v accessVariable, stack stack) (any, ArErr) { @@ -112,13 +112,13 @@ func nameToTranslated(code UNPARSEcode, index int, lines []UNPARSEcode) (any, bo realcode: code.realcode, line: code.line, path: code.path, - }, index, lines, false) + }, index, lines, 0) return setFunction{toset: value, params: params}, success, err, i } - return translateVal(code, index, lines, false) + return translateVal(code, index, lines, 0) } -func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { +func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode, isLine int) (setVariable, bool, ArErr, int) { trim := strings.TrimSpace(code.code) equalsplit := strings.SplitN(trim, "=", 2) spacesplit := strings.SplitN(equalsplit[0], " ", 2) @@ -128,9 +128,9 @@ func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVari 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) + toset, success, err, namei := nameToTranslated(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines) if err.EXISTS { - return setVariable{}, success, err, i + return setVariable{}, success, err, namei } switch toset.(type) { case accessVariable: @@ -145,14 +145,14 @@ func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVari 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) + value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, isLine) if !success { return setVariable{}, false, err, 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 + return setVariable{TYPE: "let", toset: toset, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i + namei - 1 } -func parseAutoAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { +func parseAutoAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode, isLine int) (setVariable, bool, ArErr, int) { trim := strings.TrimSpace(code.code) equalsplit := strings.SplitN(trim, "=", 2) name := strings.TrimSpace(equalsplit[0]) @@ -161,9 +161,9 @@ func parseAutoAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (s 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) + toset, success, err, namei := nameToTranslated(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines) if err.EXISTS { - return setVariable{}, success, err, i + return setVariable{}, success, err, namei } switch toset.(type) { case accessVariable: @@ -177,11 +177,11 @@ func parseAutoAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (s 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) + value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, isLine) 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 + return setVariable{TYPE: "auto", toset: toset, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i + namei - 1 } func setVariableValue(v setVariable, stack stack) (any, ArErr) { @@ -193,6 +193,10 @@ func setVariableValue(v setVariable, stack stack) (any, ArErr) { if err.EXISTS { return nil, err } + switch x := respp.(type) { + case PassBackJumpStatment: + respp = x.value + } resp = respp } @@ -238,7 +242,7 @@ func parseDelete(code UNPARSEcode, index int, lines []UNPARSEcode) (ArDelete, bo if blockedVariableNames[name] { return ArDelete{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 } - toset, success, err, i := translateVal(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines, false) + toset, success, err, i := translateVal(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines, 0) if !success { return ArDelete{}, false, err, i diff --git a/test.ar b/test.ar index c9c7d30..d3de4c9 100644 --- a/test.ar +++ b/test.ar @@ -1 +1,5 @@ -range(1e10) \ No newline at end of file +f(x) = do + x = x + 1 + x = x + 1 + return x +term.log(f(1)) \ No newline at end of file