all repos — min @ 6482875ac5918f3b68f5d5c2c3de1ec1376cd469

A small but practical concatenative programming language.

interpreter.nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
import streams, strutils, tables
import parser

type 
  TMinInterpreter* = object
    stack: TMinStack
    parser*: TMinParser
    currSym: TMinValue
    filename: string
  TMinOperator* = proc (i: var TMinInterpreter)
  TMinError* = enum
    errParser,
    errGeneric,
    errEmptyStack,
    errNoQuotation,
    errUndefined

const ERRORS: array [TMinError, string] = [
  "A parsing error occurred",
  "A generic error occurred",
  "The stack is empty", 
  "Quotation not found on the stack",
  "Symbol undefined"
]

var SYMBOLS* = initTable[string, TMinOperator]()
var TYPES* = initTable[string, TMinKind]()

TYPES["int"] = minInt
TYPES["float"] = minFloat
TYPES["string"] = minString
TYPES["symbol"] = minSymbol
TYPES["quotation"] = minQuotation


proc newMinInterpreter*(): 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: ""))
  return i

proc error*(i: TMinInterpreter, status: TMinError, message = "") =
  var msg = if message == "": ERRORS[status] else: message
  stderr.writeln("$1[$2,$3] `$4`: Error - $5" %[i.filename, $i.currSym.line, $i.currSym.last, i.currSym.symVal, msg])
  quit(int(status))

proc open*(i: var TMinInterpreter, stream:PStream, filename: string) =
  i.parser.open(stream, filename)

proc close*(i: var TMinInterpreter) = 
  i.parser.close();

proc push*(i: var TMinInterpreter, val: TMinValue) = 
  i.stack.add(val)

proc pop*(i: var TMinInterpreter): TMinValue =
  if i.stack.len > 0:
    return i.stack.pop
  else:
    i.error(errEmptyStack)

proc peek*(i: TMinInterpreter): TMinValue = 
  if i.stack.len > 0:
    return i.stack[i.stack.len-1]
  else:
    i.error(errEmptyStack)

proc interpret*(i: var TMinInterpreter) = 
  var val: TMinValue
  while i.parser.token != tkEof: 
    try:
      val = i.parser.parseMinValue
    except:
      i.error errParser, getCurrentExceptionMsg()
    if val.kind == minSymbol:
      i.currSym = val
      if SYMBOLS.hasKey val.symVal:
        SYMBOLS[val.symVal](i) 
      else:
        i.error(errUndefined, "Undefined symbol: '"&val.symVal&"'")
    else:
      i.push val