all repos — min @ 14d4c4a3e87bcea1940456a4306191125f896698

A small but practical concatenative programming language.

Re-implemented exceptions using dictionaries.
h3rald h3rald@h3rald.com
Sat, 22 Oct 2016 13:15:33 +0200
commit

14d4c4a3e87bcea1940456a4306191125f896698

parent

53f5cbd09de52317cd20e1f31bbb8469616ce35d

7 files changed, 125 insertions(+), 69 deletions(-)

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

@@ -10,6 +10,7 @@ value,

parser type + MinTrappedException* = ref object of SystemError MinRuntimeError* = ref object of SystemError qVal*: seq[MinValue]

@@ -139,7 +140,6 @@ stackcopy: stackcopy,

scope: scope, debugging: debugging, unsafe: false, - halt: false, currSym: MinValue(column: 1, line: 1, kind: minSymbol, symVal: "") ) return i

@@ -158,13 +158,13 @@ proc formatError(sym: MinValue, message: string): string =

if sym.filename.isNil or sym.filename == "": return "(!) `$1`: $2" % [sym.symVal, message] else: - return "(!) $1:$2,$3 `$4`: $5" % [sym.filename, $sym.line, $sym.column, sym.symVal, message] + return "(!) $1($2,$3) `$4`: $5" % [sym.filename, $sym.line, $sym.column, sym.symVal, message] proc formatTrace(sym: MinValue): string = if sym.filename.isNil or sym.filename == "": return " - [native] in symbol: $1" % [sym.symVal] else: - return " - $1:$2,$3 in symbol: $4" % [sym.filename, $sym.line, $sym.column, sym.symVal] + return " - $1($2,$3) in symbol: $4" % [sym.filename, $sym.line, $sym.column, sym.symVal] proc stackTrace(i: In) = var trace = i.trace

@@ -175,22 +175,7 @@

proc error(i: In, message: string) = stderr.writeLine i.currSym.formatError(message) -template execute(i: In, body: untyped) = - var stack: MinStack - if i.trace.len == 0: - i.stackcopy = i.stack - try: - body - except MinRuntimeError: - i.stack = i.stackcopy - stderr.writeLine("(!) $1:$2,$3 $4" % [i.currSym.filename, $i.currSym.line, $i.currSym.column, getCurrentExceptionMsg()]) - i.stackTrace - i.halt = true - except: - i.stack = i.stackcopy - i.error(getCurrentExceptionMsg()) - i.stackTrace - i.halt = true +#template execute(i: In, body: untyped) = proc open*(i: In, stream:Stream, filename: string) = i.filename = filename

@@ -216,8 +201,6 @@ else:

i.push(op.val) proc push*(i: In, val: MinValue) = - if i.halt: - return i.debug val if val.kind == minSymbol: i.trace.add val

@@ -229,31 +212,35 @@ let found = i.scope.hasSymbol(symbol)

if found: let sym = i.scope.getSymbol(symbol) if i.unsafe: - let stack = i.stack - try: - i.apply(sym) - except: - i.stack = stack - raise + i.apply(sym) + #if i.unsafe: + #let stack = i.stack + #try: + # i.apply(sym) + #except: + # echo "yeah!" + # i.stack = stack + # raise else: - i.execute: - i.apply(sym) + #i.execute: + i.apply(sym) else: let found = i.scope.hasSigil(sigil) if symbol.len > 1 and found: let sig = i.scope.getSigil(sigil) let sym = symbol[1..symbol.len-1] i.stack.add(MinValue(kind: minString, strVal: sym)) - if i.unsafe: - let stack = i.stack - try: - i.apply(sig) - except: - i.stack = stack - raise - else: - i.execute: - i.apply(sig) + #if i.unsafe: + #let stack = i.stack + #try: + # i.apply(sig) + #except: + # echo "yup!" + # i.stack = stack + # raise + #else: + #i.execute: + i.apply(sig) else: raiseUndefined("Undefined symbol '$1' in scope '$2'" % [val.symVal, i.scope.fullname]) discard i.trace.pop

@@ -278,10 +265,26 @@ raiseEmptyStack()

proc interpret*(i: In) {.gcsafe.}= var val: MinValue - while i.parser.token != tkEof and not i.halt: - i.execute: + while i.parser.token != tkEof: + if i.trace.len == 0: + i.stackcopy = i.stack + try: val = i.parser.parseMinValue i.push val + except MinRuntimeError: + let msg = getCurrentExceptionMsg() + i.stack = i.stackcopy + stderr.writeLine("(!) $1:$2,$3 $4" % [i.currSym.filename, $i.currSym.line, $i.currSym.column, msg]) + i.stackTrace + raise MinTrappedException(msg: msg) + except MinTrappedException: + raise + except: + let msg = getCurrentExceptionMsg() + i.stack = i.stackcopy + i.error(msg) + i.stackTrace + raise MinTrappedException(msg: msg) proc unquote*(i: In, name: string, q: var MinValue) = i.createScope(name, q):

@@ -289,8 +292,8 @@ for v in q.qVal:

i.push v proc eval*(i: In, s: string, name="<eval>") = - let fn = i.filename - try: + #let fn = i.filename + #try: var i2 = i.copy(name) i2.open(newStringStream(s), name) discard i2.parser.getToken()

@@ -299,14 +302,15 @@ i.trace = i2.trace

i.stackcopy = i2.stackcopy i.stack = i2.stack i.scope = i2.scope - except: - stderr.writeLine getCurrentExceptionMsg() - finally: - i.filename = fn + #except: + # stderr.writeLine getCurrentExceptionMsg() + # raise + #finally: + # i.filename = fn proc load*(i: In, s: string) = - let fn = i.filename - try: + #let fn = i.filename + #try: var i2 = i.copy(s) i2.open(newStringStream(s.readFile), s) discard i2.parser.getToken()

@@ -315,7 +319,8 @@ i.trace = i2.trace

i.stackcopy = i2.stackcopy i.stack = i2.stack i.scope = i2.scope - except: - stderr.writeLine getCurrentExceptionMsg() - finally: - i.filename = fn + #except: + # stderr.writeLine getCurrentExceptionMsg() + # raise + #finally: + # i.filename = fn
M core/parser.nimcore/parser.nim

@@ -100,7 +100,6 @@ filename*: string

debugging*: bool evaluating*: bool unsafe*: bool - halt*: bool MinParsingError* = ref object of ValueError MinUndefinedError* = ref object of ValueError MinEmptyStackError* = ref object of ValueError
M lib/min_lang.nimlib/min_lang.nim

@@ -23,6 +23,13 @@ if v.qVal[0].getString == s.getString:

return v.qVal[1] raiseInvalid("Key '$1' not found" % s.getString) +proc dhas*(q: MinValue, s: MinValue): bool = + # Assumes q is a dictionary + for v in q.qVal: + if v.qVal[0].getString == s.getString: + return true + return false + proc ddel*(q: var MinValue, s: MinValue): MinValue = # Assumes q is a dictionary var found = false

@@ -313,9 +320,36 @@

# ("SomeError" "message") .symbol("raise") do (i: In): var err: MinValue - i.reqQuotation err - raiseRuntime("($1) $2" % [err.qVal[0].getString, err.qVal[1].getString], err.qVal) + i.reqDictionary err + if err.dhas("error".newSym) and err.dhas("message".newSym): + # TODO rewrite as dictionary! + raiseRuntime("($1) $2" % [err.dget("error".newVal).getString, err.dget("message".newVal).getString], err.qVal) + else: + raiseInvalid("Invalid error dictionary") + .symbol("format-error") do (i: In): + var err: MinValue + i.reqDictionary err + if err.dhas("error".newSym) and err.dhas("message".newSym): + var msg: string + var list = newSeq[MinValue]() + list.add err.dget("message".newVal) + if err.qVal.contains("symbol".newVal): + list.add err.dget("symbol".newVal) + if err.qVal.contains("filename".newVal): + list.add err.dget("filename".newVal) + if err.qVal.contains("line".newVal): + list.add err.dget("line".newVal) + if err.qVal.contains("column".newVal): + list.add err.dget("column".newVal) + if list.len <= 1: + msg = "(!) $1" % $$list[0] + else: + msg = "(!) $3($4,$5) `$2`: $1" % [$$list[0], $$list[1], $$list[2], $$list[3], $$list[4]] + i.push msg.newVal + else: + raiseInvalid("Invalid error dictionary") + .symbol("try") do (i: In): var prog: MinValue i.reqQuotation prog

@@ -348,7 +382,15 @@ if not hasCatch:

return i.unsafe = false let e = getCurrentException() - i.push @[regex.replace($e.name, ":.+$", "").newVal, e.msg.newVal].newVal + var res = newSeq[MinValue](0) + let err = regex.replace($e.name, ":.+$", "") + res.add @["error".newSym, err.newVal].newVal + res.add @["message".newSym, e.msg.newVal].newVal + res.add @["symbol".newSym, i.currSym].newVal + res.add @["filename".newSym, i.currSym.filename.newVal].newVal + res.add @["line".newSym, i.currSym.line.newVal].newVal + res.add @["column".newSym, i.currSym.column.newVal].newVal + i.push res.newVal i.unquote("<try-catch>", catch) finally: if hasFinally:

@@ -611,11 +653,16 @@ i.linrec(p, t, r1, r2)

i.unquote("<linrec-r2>", r2) i.linrec(p, t, r1, r2) + .symbol("dhas?") do (i: In): + var d, k: MinValue + i.reqStringLike k + i.reqDictionary d + i.push d.dhas(k).newVal + .symbol("dget") do (i: In): var d, k: MinValue i.reqStringLike k i.reqDictionary d - #i.push d i.push d.dget(k) .symbol("dset") do (i: In):
M minim.nimminim.nim

@@ -129,8 +129,12 @@ i.pwd = filename.parentDir

i.stdLib() i.open(s, filename) discard i.parser.getToken() - i.interpret() + try: + i.interpret() + except: + discard i.close() + quit() proc minimString*(buffer: string, debugging = false) = minimStream(newStringStream(buffer), "input", debugging)

@@ -172,9 +176,9 @@ discard i.parser.getToken()

try: i.interpret() except: - stderr.writeLine getCurrentExceptionMsg() + discard + #stderr.writeLine getCurrentExceptionMsg() finally: - i.halt = false if i.stack.len > 0: let last = i.stack[i.stack.len - 1] let n = $i.stack.len
M minim.vimminim.vim

@@ -12,7 +12,7 @@ setl iskeyword+=?,$,+,*,/,%,=,>,<,&,-,',.,:,~,!

setl iskeyword+=^ setl iskeyword+=@ -syntax keyword minimDefaultSymbol ! != $ & ' * + - % ^ -> . .. / : < <= == => =~ > >= @ ROOT aes and append apply ask at atime b bind bool bool? bury1 bury2 bury3 c call call! capitalize case cd chmod choose clear-stack column-print concat confirm cons cp cpu crypto ctime datetime ddel debug debug? decode decrypt define define* delete dget dictionary? dig1 dig2 dig3 dip dir? dirname div dprint dprint! dset dump-stack dup dupd echo encode encrypt env? eq eval even? exit fappend file? filename filter first float float? foreach fperms fread from-json fs fsize fstats ftype fwrite gets get-stack getenv gt gte hardlink hidden? i id ifte import include indent inspect int int? interpolate interval io join k keys length linrec load load-symbol logic lowercase ls ls-r lt lte map match md5 mkdir mod module mtime mv newline not noteq now num number? odd? or os password pop popd pred prepend print print! prompt publish puts puts! putenv q quit quotation? quote raise regex remove-symbol repeat replace rest rm rmdir run save-symbol scope scope? seal search select set-stack sha1 sha224 sha256 sha384 sha512 sigils sip size sleep sort source split startup stored-symbols str string string? strip succ swap swapd swons symbols symlink symlink? sys system take tformat time timeinfo times timestamp titleize to-json try unit unquote uppercase unzip values version which while with xor zap zip contains +syntax keyword minimDefaultSymbol ! != $ & ' * + - % ^ -> . .. / : < <= == => =~ > >= @ ROOT aes and append apply ask at atime b bind bool bool? bury1 bury2 bury3 c call call! capitalize case cd chmod choose clear-stack column-print concat confirm cons cp cpu crypto ctime datetime ddel debug debug? decode decrypt define define* delete dget dictionary? dig1 dig2 dig3 dip dir? dirname div dprint dprint! dset dump-stack dup dupd echo encode encrypt env? eq eval even? exit fappend file? filename filter first float float? foreach fperms fread from-json format-error fs fsize fstats ftype fwrite gets get-stack getenv gt gte hardlink hidden? i id ifte import include indent inspect int int? interpolate interval io join k keys length linrec load load-symbol logic lowercase ls ls-r lt lte map match md5 mkdir mod module mtime mv newline not noteq now num number? odd? or os password pop popd pred prepend print print! prompt publish puts puts! putenv q quit quotation? quote raise regex remove-symbol repeat replace rest rm rmdir run save-symbol scope scope? seal search select set-stack sha1 sha224 sha256 sha384 sha512 sigils sip size sleep sort source split startup stored-symbols str string string? strip succ swap swapd swons symbols symlink symlink? sys system take tformat time timeinfo times timestamp titleize to-json try unit unquote uppercase unzip values version which while with xor zap zip contains syntax match minimDefaultSigil ;\<[:@'~!$%&$=<>^*]; contained
M tests/lang.mintests/lang.min

@@ -105,12 +105,13 @@ ((1 2 3 4 5) (even?) filter (2 4) ==) assert

(5 (dup 0 ==) (1 +) (dup 1 -) ( * ) linrec 120 ==) assert ;factorial of 5 + ( ( (pop) - (first) - ("Caught a " swap concat) - ) try "Caught a MinEmptyStackError" ==) assert + ('error dget) + ("finally") + ) try get-stack ("MinEmptyStackError" "finally") ==) assert ("aaaa" :cd cd "aaaa" ==) assert ;It is possible to shadow sealed symbols in child scopes

@@ -118,9 +119,9 @@ (((2 :a1 *a1 3 :a1) ("failed")) try "failed" ==) assert

( ( - (("TestError" "Test Message") raise) - (1 at) - ) try "Test Message" ==) assert + (((error "TestError")(message "Test Message")) raise) + ('error dget) + ) try "TestError" ==) assert ( (("test" (1 2) :)) try get-stack ("test") ==) assert
M tests/test.mintests/test.min

@@ -18,7 +18,7 @@ ' :results ; save the result symbol to update

( ( (check -> true ==) - (1 at :err "\nError: $1" (err) % puts false) + (format-error puts! false) ) try )