all repos — min @ adb07b0894a9fadef787589ec7d8773f85107fab

A small but practical concatenative programming language.

Implemented debug mode.
h3rald h3rald@h3rald.com
Sun, 23 Nov 2014 15:44:34 +0100
commit

adb07b0894a9fadef787589ec7d8773f85107fab

parent

b7717dc7bc7a9281d758f84fecf8a1133ca8679c

4 files changed, 63 insertions(+), 28 deletions(-)

jump to
M interpreter.niminterpreter.nim

@@ -7,8 +7,10 @@ stack: TMinStack

parser*: TMinParser currSym: TMinValue filename: string + debugging: bool TMinOperator* = proc (i: var TMinInterpreter) TMinError* = enum + errSystem, errParser, errGeneric, errEmptyStack,

@@ -20,6 +22,7 @@ errDivisionByZero

const ERRORS: array [TMinError, string] = [ + "A system error occurred", "A parsing error occurred", "A generic error occurred", "The stack is empty",

@@ -32,10 +35,10 @@ ]

var SYMBOLS* = initTable[string, TMinOperator]() -proc newMinInterpreter*(): TMinInterpreter = +proc newMinInterpreter*(debugging = false): TMinInterpreter = var s:TMinStack = newSeq[TMinValue](0) var p:TMinParser - var i:TMinInterpreter = TMinInterpreter(filename: "input", parser: p, stack: s, currSym: TMinValue(first: 0, last: 0, line: 0, kind: minSymbol, symVal: "")) + var i:TMinInterpreter = TMinInterpreter(filename: "input", parser: p, stack: s, debugging: debugging, currSym: TMinValue(first: 0, last: 0, line: 0, kind: minSymbol, symVal: "")) return i proc error*(i: TMinInterpreter, status: TMinError, message = "") =

@@ -50,11 +53,25 @@

proc close*(i: var TMinInterpreter) = i.parser.close(); +proc dump*(i: TMinInterpreter): string = + var s = "" + for item in i.stack: + s = s & $item & " " + return s.strip + +proc debug(i: var TMinInterpreter, value: string = "") = + if i.debugging: + stderr.writeln("DEBUG: " &i.dump & value) + proc push*(i: var TMinInterpreter, val: TMinValue) = if val.kind == minSymbol: i.currSym = val - if SYMBOLS.hasKey val.symVal: - SYMBOLS[val.symVal](i) + i.debug " "&val.symVal + if SYMBOLS.hasKey(val.symVal): + try: + SYMBOLS[val.symVal](i) + except: + i.error(errSystem, getCurrentExceptionMsg()) else: i.error(errUndefined, "Undefined symbol: '"&val.symVal&"'") else:

@@ -71,12 +88,6 @@ if i.stack.len > 0:

return i.stack[i.stack.len-1] else: i.error(errEmptyStack) - -proc dump*(i: TMinInterpreter) = - for item in i.stack: - item.print - stdout.write " " - stdout.writeln "" proc interpret*(i: var TMinInterpreter) = var val: TMinValue
M minim.nimminim.nim

@@ -3,6 +3,8 @@ import parser, interpreter, primitives

const version* = "0.1.0" +var debugging = false +var repl = false let usage* = " MiNiM v" & version & " - a tiny concatenative programming language" & """

@@ -20,7 +22,7 @@ -v, --version Print the program version

-i, --interactive Starts MiNiM's Read Evel Print Loop""" proc minimStream(s: PStream, filename: string) = - var i = newMinInterpreter() + var i = newMinInterpreter(debugging) i.open(s, filename) discard i.parser.getToken() i.interpret()

@@ -49,7 +51,7 @@ stderr.flushFile()

minimStream(stream, filename) proc minimRepl*() = - var i = newMinInterpreter() + var i = newMinInterpreter(debugging) var s = newStringStream("") i.open(s, "repl") setControlCHook(handleReplCtrlC)

@@ -66,7 +68,7 @@ i.parser.bufLen = i.parser.buf.len

discard i.parser.getToken() i.interpret() stdout.write "-> " - i.dump + echo i.dump ###

@@ -78,6 +80,8 @@ of cmdArgument:

file = key of cmdLongOption, cmdShortOption: case key: + of "debug", "d": + debugging = true of "evaluate", "e": str = val of "help", "h":

@@ -85,8 +89,7 @@ echo usage

of "version", "v": echo version of "interactive", "i": - minimRepl() - quit(0) + repl = true else: discard

@@ -94,5 +97,9 @@ if str != "":

minimString(str) elif file != "": minimFile file +elif repl: + minimRepl() + quit(0) else: minimFile stdin +
M parser.nimparser.nim

@@ -130,9 +130,9 @@

proc raiseUndefinedError*(p:TMinParser, msg: string) {.noinline, noreturn.} = raise EMinUndefinedError(msg: errorMsg(p, msg)) -proc error(p: TMinParser, msg: string) = - writeln(stderr, p.errorMsg(msg)) - flushFile(stderr) +#proc error(p: TMinParser, msg: string) = +# writeln(stderr, p.errorMsg(msg)) +# flushFile(stderr) proc parseNumber(my: var TMinParser) = var pos = my.bufpos

@@ -411,20 +411,23 @@ discard getToken(p)

else: raiseUndefinedError(p, "Undefined value: '"&p.a&"'") -proc print*(a: TMinValue) = +proc `$`*(a: TMinValue): string = case a.kind: of minSymbol: - stdout.write a.symVal + return a.symVal of minString: - stdout.write "\""&a.strVal&"\"" + return "\""&a.strVal&"\"" of minInt: - stdout.write a.intVal + return $a.intVal of minFloat: - stdout.write a.floatVal + return $a.floatVal of minQuotation: - stdout.write "[ " + var q = "[ " for i in a.qVal: - i.print - stdout.write " " - stdout.write "]" + q = q & $i & " " + q = q & "]" + return q + +proc print*(a: TMinValue) = + stdout.write($a)
M primitives.nimprimitives.nim

@@ -56,7 +56,7 @@

# Operations on the whole stack minsym "dump": - i.dump + echo i.dump # Operations on quotations or strings

@@ -166,7 +166,21 @@ i.push newFloat(b.intVal.float / a.floatVal)

else: i.error(errTwoNumbersRequired) +# Language constructs +minsym "def": + let q1 = i.pop + let q2 = i.pop + if q1.isQuotation and q2.isQuotation: + if q1.qVal.len == 1 and q1.qVal[0].kind == minSymbol: + minsym q1.qVal[0].symVal: + for item in q2.qVal: + i.push item + else: + i.error(errIncorrect, "The top quotation must contain only one symbol value") + else: + i.error(errIncorrect, "Two quotations or two strings is required on the stack") minalias "&", "concat" minalias "%", "print" +minalias ":", "def"