diff --git a/src/comment.go b/src/comment.go index 2531673..88ea77d 100644 --- a/src/comment.go +++ b/src/comment.go @@ -14,16 +14,18 @@ func isBlank(code UNPARSEcode) bool { return strings.TrimSpace(code.code) == "" } -func parseComment(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr) { +func parseComment(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, ArErr, int) { split := strings.Split(code.code, "#") temp := []string{} + step := 1 for i := 0; i < len(split)-1; i++ { temp = append(temp, split[i]) joined := strings.Join(temp, "#") - resp, worked, _, _ := 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, true) + step += s - 1 if worked { - return resp, true, ArErr{} + return resp, true, ArErr{}, step } } - return nil, false, ArErr{"Syntax Error", "invalid comment", code.line, code.path, code.realcode, true} + return nil, false, ArErr{"Syntax Error", "invalid comment", code.line, code.path, code.realcode, true}, step } diff --git a/src/number.go b/src/number.go index 90b9dff..a8b6041 100644 --- a/src/number.go +++ b/src/number.go @@ -63,6 +63,8 @@ func numberToString(num number, fraction int, simplify bool) string { floated := float64(int(divPI * 100)) if divPI == 1 { return "π" + } else if divPI == -1 { + return "-π" } else if divPI == 0 { return "0" } else if (divPI*100) == floated && floated != 0 { diff --git a/src/operations.go b/src/operations.go index 7f7f459..7554c59 100644 --- a/src/operations.go +++ b/src/operations.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math" "reflect" "strings" ) @@ -243,7 +244,7 @@ func calcNegative(o operationType, stack stack) (number, ArErr) { return output, ArErr{} } -func calcDiv(o operationType, stack stack) (number, ArErr) { +func calcDivide(o operationType, stack stack) (number, ArErr) { resp, err := runVal( o.values[0], @@ -256,7 +257,7 @@ func calcDiv(o operationType, stack stack) (number, ArErr) { if !isAnyNumber(resp) { return nil, ArErr{ "Runtime Error", - "Cannot subtract from type '" + typeof(resp) + "'", + "Cannot divide from type '" + typeof(resp) + "'", o.line, o.path, o.code, @@ -480,6 +481,107 @@ func equals(a any, b any) bool { return reflect.DeepEqual(a, b) } +func calcMod(o operationType, stack stack) (number, ArErr) { + resp, err := runVal( + o.values[0], + stack, + ) + resp = classVal(resp) + if err.EXISTS { + return nil, err + } + if !isAnyNumber(resp) { + return nil, ArErr{ + "Runtime Error", + "Cannot calculate modulus from type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } + output := newNumber().Set(resp.(number)) + for i := 1; i < len(o.values); i++ { + resp, err := runVal( + o.values[i], + stack, + ) + resp = classVal(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) == "number" { + n1, _ := output.Float64() + n2, _ := resp.(number).Float64() + output = newNumber().SetFloat64(math.Mod(n1, n2)) + } else { + return nil, ArErr{ + "Runtime Error", + "Cannot calculate modulus of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } + } + return output, ArErr{} +} + +func calcIntDiv(o operationType, stack stack) (number, ArErr) { + resp, err := calcDivide(o, stack) + x, _ := resp.Float64() + resp = newNumber().SetFloat64(math.Trunc(x)) + return resp, err +} + +func calcPower(o operationType, stack stack) (number, ArErr) { + resp, err := runVal( + o.values[0], + stack, + ) + resp = classVal(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) != "number" { + return nil, ArErr{ + "Runtime Error", + "Cannot calculate power of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } + output := newNumber().Set(resp.(number)) + for i := 1; i < len(o.values); i++ { + resp, err := runVal( + o.values[i], + stack, + ) + resp = classVal(resp) + if err.EXISTS { + return nil, err + } + if typeof(resp) == "number" { + n1, _ := output.Float64() + n2, _ := resp.(number).Float64() + output = newNumber().SetFloat64(math.Pow(n1, n2)) + } else { + return nil, ArErr{ + "Runtime Error", + "Cannot calculate power of type '" + typeof(resp) + "'", + o.line, + o.path, + o.code, + true, + } + } + } + return output, ArErr{} +} + func runOperation(o operationType, stack stack) (any, ArErr) { switch o.operation { case 0: @@ -511,7 +613,13 @@ func runOperation(o operationType, stack stack) (any, ArErr) { case 12: return calcMul(o, stack) case 13: - return calcDiv(o, stack) + return calcMod(o, stack) + case 14: + return calcIntDiv(o, stack) + case 15: + return calcDivide(o, stack) + case 16: + return calcPower(o, stack) } panic("Unknown operation: " + fmt.Sprint(o.operation)) diff --git a/src/run.go b/src/run.go index 033fa7c..4593f9f 100644 --- a/src/run.go +++ b/src/run.go @@ -48,6 +48,8 @@ func runVal(line any, stack stack) (any, ArErr) { return runVal(x.VAL, stack) case operationType: return runOperation(x, stack) + case ArDelete: + return runDelete(x, stack) } fmt.Println("unreachable", reflect.TypeOf(line)) panic("unreachable") diff --git a/src/translate.go b/src/translate.go index 0bc3c81..f3d0ced 100644 --- a/src/translate.go +++ b/src/translate.go @@ -13,10 +13,12 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b if isLine { if isBlank(code) { return nil, true, ArErr{}, 1 + } else if isDeleteVariable(code) { + return parseDelete(code, index, codelines) } else if isComment(code) { - resp, worked, err := parseComment(code, index, codelines) + resp, worked, err, step := parseComment(code, index, codelines) if worked { - return resp, worked, err, 1 + return resp, worked, err, step } } } diff --git a/src/variable.go b/src/variable.go index 9c968f4..53f8932 100644 --- a/src/variable.go +++ b/src/variable.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "strings" ) @@ -9,7 +8,7 @@ var variableCompile = makeRegex(`( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{ 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 deleteVariableCompile = makeRegex(`( *)delete( +)(.|\n)+( *)`) var blockedVariableNames = map[string]bool{ "if": true, @@ -53,6 +52,13 @@ type setFunction struct { params []string } +type ArDelete struct { + value any + line int + code string + path string +} + func isVariable(code UNPARSEcode) bool { return variableCompile.MatchString(code.code) } @@ -92,9 +98,7 @@ func nameToTranslated(code UNPARSEcode, index int, lines []UNPARSEcode) (any, bo 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{ @@ -185,7 +189,7 @@ func setVariableValue(v setVariable, stack stack) (any, ArErr) { if v.TYPE == "let" { 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} + return nil, ArErr{"Runtime Error", "variable \"" + v.toset.(accessVariable).name + "\" already exists", v.line, v.path, v.code, true} } stack[len(stack)-1][v.toset.(accessVariable).name] = resp } else { @@ -218,24 +222,53 @@ func setVariableValue(v setVariable, stack stack) (any, ArErr) { return resp, ArErr{} } -/* - -func parseAutosAsignVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) { +func parseDelete(code UNPARSEcode, index int, lines []UNPARSEcode) (ArDelete, bool, ArErr, int) { trim := strings.TrimSpace(code.code) - equalsplit := strings.SplitN(trim, "=", 2) - name := strings.TrimSpace(equalsplit[0]) - params := []string{} - function := false - + spacesplit := strings.SplitN(trim, " ", 2) + name := strings.TrimSpace(spacesplit[1]) if blockedVariableNames[name] { - return setVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1 + return ArDelete{}, 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) + toset, success, err, i := translateVal(UNPARSEcode{code: name, realcode: code.realcode, line: code.line, path: code.path}, index, lines, false) + if !success { - return setVariable{}, false, err, i + return ArDelete{}, 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 + return ArDelete{ + toset, + code.line, + code.code, + code.path, + }, true, ArErr{}, i } - -*/ +func runDelete(d ArDelete, stack stack) (any, ArErr) { + switch x := d.value.(type) { + case accessVariable: + for i := len(stack) - 1; i >= 0; i-- { + if _, ok := stack[i][x.name]; ok { + delete(stack[i], x.name) + return nil, ArErr{} + } + } + return nil, ArErr{"Runtime Error", "variable \"" + x.name + "\" does not exist", d.line, d.path, d.code, true} + 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: + delete(y, key) + default: + return nil, ArErr{"Runtime Error", "can't delete for non map", d.line, d.path, d.code, true} + } + default: + return nil, ArErr{"Runtime Error", "can't delete for non variable", d.line, d.path, d.code, true} + } + return nil, ArErr{} +}