diff --git a/src/getIndex.go b/src/getIndex.go index 6cd912b..6d82ded 100644 --- a/src/getIndex.go +++ b/src/getIndex.go @@ -152,7 +152,7 @@ func indexGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapG return ArMapGet{tival, args, true, code.line, code.realcode, code.path}, true, ArErr{}, 1 } return ArMapGet{}, false, ArErr{ - "SyntaxError", + "Syntax Error", "invalid index get", code.line, code.path, diff --git a/src/run.go b/src/run.go index 0d509a2..b42f702 100644 --- a/src/run.go +++ b/src/run.go @@ -197,6 +197,14 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) { break } return runAbs(x, stack, stacklevel+1) + case TryCatch: + if stackoverflow { + linenum = x.line + path = x.path + code = x.code + break + } + return runTryCatch(x, stack, stacklevel+1) case bool, ArObject, number, nil: return x, ArErr{} } diff --git a/src/translate.go b/src/translate.go index d2e3257..be99262 100644 --- a/src/translate.go +++ b/src/translate.go @@ -42,6 +42,8 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine i return parseForLoop(code, index, codelines) } else if isGenericImport(code) { return parseGenericImport(code, index, codelines) + } else if isTryCatch(code) { + return parseTryCatch(code, index, codelines) } } diff --git a/src/trycatch.go b/src/trycatch.go new file mode 100644 index 0000000..bd4a9db --- /dev/null +++ b/src/trycatch.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "strings" +) + +var tryCompiled = makeRegex(`\s*try\s(.|\n)+`) +var catchCompiled = makeRegex(`\s*catch\s*\(\s*` + spacelessVariable + `\s*\)\s*(.|\n)+`) + +type TryCatch struct { + Try any + Catch any + errorName string + line int + path string + code string +} + +func isTryCatch(code UNPARSEcode) bool { + return tryCompiled.MatchString(code.code) +} + +func parseTryCatch(code UNPARSEcode, index int, codelines []UNPARSEcode) (TryCatch, bool, ArErr, int) { + trytrimmed := strings.TrimSpace(code.code) + totalIndex := 0 + tryparsed, worked, err, i := translateVal(UNPARSEcode{trytrimmed[4:], code.realcode, code.line, code.path}, index, codelines, 1) + if !worked { + return TryCatch{}, false, err, i + } + totalIndex += i + catchtrimmed := strings.TrimSpace(codelines[index+totalIndex].code) + if !catchCompiled.MatchString(catchtrimmed) { + fmt.Println(catchtrimmed) + return TryCatch{}, false, ArErr{"Syntax Error", "invalid syntax", code.line, code.path, code.realcode, true}, i + } + catchtrimmed = catchtrimmed[6:] + catchbracketSplit := strings.SplitN(catchtrimmed, ")", 2) + errorName := strings.TrimSpace(strings.TrimSpace(catchbracketSplit[0])[1:]) + errcode := catchbracketSplit[1] + + catchparsed, worked, err, i := translateVal(UNPARSEcode{errcode, code.realcode, code.line, code.path}, index+totalIndex, codelines, 1) + if !worked { + return TryCatch{}, false, err, i + } + totalIndex += i + + return TryCatch{ + tryparsed, + catchparsed, + errorName, + code.line, + code.path, + code.realcode, + }, true, ArErr{}, totalIndex +} + +func runTryCatch(t TryCatch, stack stack, stacklevel int) (any, ArErr) { + val, err := runVal(t.Try, stack, stacklevel) + if err.EXISTS { + scope := newscope() + scope.obj[t.errorName] = Map(anymap{ + "type": err.TYPE, + "message": err.message, + "line": newNumber().SetInt64(int64(err.line)), + "path": err.path, + "code": err.code, + }) + val, err = runVal(t.Catch, append(stack, scope), stacklevel) + if err.EXISTS { + return nil, err + } + } + return val, ArErr{} +} diff --git a/src/variable.go b/src/variable.go index b689e18..37b8bfd 100644 --- a/src/variable.go +++ b/src/variable.go @@ -35,6 +35,8 @@ var blockedVariableNames = map[string]bool{ "not": true, "and": true, "or": true, + "try": true, + "catch": true, } type accessVariable struct { @@ -85,7 +87,7 @@ func readVariable(v accessVariable, stack stack) (any, ArErr) { return val, ArErr{} } } - return nil, ArErr{"Runtime Error", "variable \"" + v.name + "\" does not exist", v.line, v.path, v.code, true} + return nil, ArErr{"Name Error", "variable \"" + v.name + "\" does not exist", v.line, v.path, v.code, true} } func isSetVariable(code UNPARSEcode) bool { @@ -212,7 +214,7 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) { _, ok := stack[len(stack)-1].obj[v.toset.(accessVariable).name] varMutex.RUnlock() if ok { - return nil, ArErr{"Runtime Error", "variable \"" + v.toset.(accessVariable).name + "\" already exists", v.line, v.path, v.code, true} + return nil, ArErr{"Name Error", "variable \"" + v.toset.(accessVariable).name + "\" already exists", v.line, v.path, v.code, true} } varMutex.Lock() stack[len(stack)-1].obj[v.toset.(accessVariable).name] = resp @@ -307,7 +309,7 @@ func runDelete(d ArDelete, stack stack, stacklevel int) (any, ArErr) { return nil, ArErr{} } } - return nil, ArErr{"Runtime Error", "variable \"" + x.name + "\" does not exist", d.line, d.path, d.code, true} + return nil, ArErr{"Name Error", "variable \"" + x.name + "\" does not exist", d.line, d.path, d.code, true} case ArMapGet: respp, err := runVal(x.VAL, stack, stacklevel+1) if err.EXISTS {