all repos — min @ 22a43dc378092f7d1e3c9597afa9b11738867062

A small but practical concatenative programming language.

feat(try) Implemented exception handling via raise and try operators.
h3rald h3rald@h3rald.com
Sat, 04 Jun 2016 13:53:01 +0200
commit

22a43dc378092f7d1e3c9597afa9b11738867062

parent

7bb38b205fbbf82cc69b6fa83f09adfb32e273e1

7 files changed, 77 insertions(+), 14 deletions(-)

jump to
M core/interpreter.nimcore/interpreter.nim

@@ -90,6 +90,7 @@ parser: pr,

stack: st, scope: ROOT, debugging: debugging, + unsafe: false, currSym: MinValue(column: 1, line: 1, kind: minSymbol, symVal: "") ) return i

@@ -126,21 +127,29 @@ let symbol = val.symVal

let sigil = "" & symbol[0] let symbolProc = i.scope.getSymbol(symbol) if not symbolProc.isNil: - try: + if i.unsafe: symbolProc(i) - except MinRuntimeError: - stderr.writeLine("$1 [$2,$3]: $4" % [i.currSym.filename, $i.currSym.line, $i.currSym.column, getCurrentExceptionMsg()]) - except: - i.error(errSystem, getCurrentExceptionMsg()) + else: + try: + symbolProc(i) + except MinRuntimeError: + stderr.writeLine("$1 [$2,$3]: $4" % [i.currSym.filename, $i.currSym.line, $i.currSym.column, getCurrentExceptionMsg()]) + except: + i.error(errSystem, getCurrentExceptionMsg()) else: let sigilProc = i.scope.getSigil(sigil) if symbol.len > 1 and not sigilProc.isNil: let sym = symbol[1..symbol.len-1] - try: - i.stack.add(MinValue(kind: minString, strVal: sym)) + i.stack.add(MinValue(kind: minString, strVal: sym)) + if i.unsafe: sigilProc(i) - except: - i.error(errSystem, getCurrentExceptionMsg()) + else: + try: + sigilProc(i) + except MinRuntimeError: + stderr.writeLine("$1 [$2,$3]: $4" % [i.currSym.filename, $i.currSym.line, $i.currSym.column, getCurrentExceptionMsg()]) + except: + i.error(errSystem, getCurrentExceptionMsg()) else: i.error(errUndefined, "Undefined symbol: '"&val.symVal&"'") return
M core/parser.nimcore/parser.nim

@@ -454,3 +454,6 @@ else:

return false else: return false + +proc isNil*(a: MinValue): bool = + return a.kind != minQuotation and a.kind != minString and a.kind != minFloat and a.kind != minInt and a.kind != minBool and a.kind != minSymbol
M core/types.nimcore/types.nim

@@ -71,6 +71,7 @@ MinStack* = seq[MinValue]

MinParsingError* = ref object of ValueError MinUndefinedError* = ref object of ValueError MinRuntimeError* = ref object of SystemError + qVal*: seq[MinValue] MinInterpreter* = object stack*: MinStack pwd*: string

@@ -80,6 +81,7 @@ currSym*: MinValue

filename*: string debugging*: bool evaluating*: bool + unsafe*: bool In* = var MinInterpreter MinOperator* = proc (i: var MinInterpreter) MinSigil* = proc (i: var MinInterpreter, sym: string)
M core/utils.nimcore/utils.nim

@@ -25,6 +25,9 @@

proc newVal*(s: string): MinValue = return MinValue(kind: minString, strVal: s) +proc newVal*(s: cstring): MinValue = + return MinValue(kind: minString, strVal: $s) + proc newVal*(q: seq[MinValue]): MinValue = return MinValue(kind: minQuotation, qVal: q)
M lib/lang.nimlib/lang.nim

@@ -3,7 +3,8 @@ import

../core/types, ../core/parser, ../core/interpreter, - ../core/utils + ../core/utils, + ../core/regex ROOT

@@ -193,7 +194,41 @@ .symbol("raise") do (i: In):

let err = i.pop if not err.isQuotation: i.error errNoQuotation - raise MinRuntimeError(msg: "($1) $2" % [err.qVal[0].getString, err.qVal[1].getString]) + raise MinRuntimeError(msg: "($1) $2" % [err.qVal[0].getString, err.qVal[1].getString], qVal: err.qVal) + + .symbol("try") do (i: In): + var prog = i.pop + if not prog.isQuotation: + i.error errNoQuotation + if prog.qVal.len < 2: + i.error errIncorrect, "Quotation must contain at least two elements" + return + var code = prog.qVal[0] + var catch = prog.qVal[1] + var final: MinValue + var hasFinally = false + if prog.qVal.len > 2: + final = prog.qVal[2] + hasFinally = true + if (not code.isQuotation or not catch.isQuotation) or (hasFinally and not final.isQuotation): + i.error errIncorrect, "Quotation must contain at least two quotations" + return + i.unsafe = true + try: + i.unquote("<try-code>", code) + except MinRuntimeError: + i.unsafe = false + let e = (MinRuntimeError)getCurrentException() + i.push e.qVal.newVal + i.unquote("<try-catch>", catch) + except: + i.unsafe = false + let e = getCurrentException() + i.push @[e.name.newVal, e.msg.newVal].newVal + i.unquote("<try-catch>", catch) + finally: + if hasFinally: + i.unquote("<try-finally>", final) # Operations on the whole stack
M lib/num.nimlib/num.nim

@@ -66,8 +66,6 @@

.symbol("/") do (i: In): let a = i.pop let b = i.pop - if b.isInt and b.intVal == 0: - i.error errDivisionByZero if a.isInt: if b.isInt: i.push newVal(b.intVal / a.intVal)
M tests/lang.mintests/lang.min

@@ -3,7 +3,7 @@ #test

"lang" describe - (symbols size 161 ==) assert + (symbols size 162 ==) assert (sigils size 10 ==) assert

@@ -86,6 +86,19 @@

((1 2 3 4 5) (even?) filter (2 4) ==) assert (5 (dup 0 ==) (1 +) (dup 1 -) ( * ) linrec 120 ==) assert ;factorial of 5 + + ( + ( + (() 1 at) + (first) + ("Caught an " swap concat) + ) try "Caught an IndexError" ==) assert + + ( + ( + (("TestError" "Test Message") raise) + (1 at) + ) try "Test Message" ==) assert report ; Tidy up