all repos — min @ 66db4625882a303b9847f316f0030fa37612095a

A small but practical concatenative programming language.

minim.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
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
import streams, tables, parseopt2, strutils
import parser, interpreter, primitives, utils, linenoise


const version* = "0.1.0"
var debugging = false
var repl = false
const prelude = "prelude.min".slurp.strip

let usage* = "  MiNiM v" & version & " - a tiny concatenative system programming language" & """

  (c) 2014 Fabio Cevasco
  
  Usage:
    minim [options] [filename]

  Arguments:
    filename  A minim file to interpret (default: STDIN).
  Options:
    -e, --evaluate    Evaluate a minim program inline
    -h, --help        Print this help
    -v, --version     Print the program version
    -i, --interactive Starts MiNiM's Read Evel Print Loop"""

proc minimStream(s: PStream, filename: string) =
  var i = newMinInterpreter(debugging)
  i.eval prelude
  i.open(s, filename)
  discard i.parser.getToken() 
  i.interpret()
  i.close()

proc minimString*(buffer: string) =
    minimStream(newStringStream(buffer), "input")

proc minimFile*(filename: string) =
  var stream = newFileStream(filename, fmRead)
  if stream == nil:
    stderr.writeln("Error - Cannot read from file: "& filename)
    stderr.flushFile()
  minimStream(stream, filename)

proc minimFile*(file: TFile, filename="stdin") =
  var stream = newFileStream(stdin)
  if stream == nil:
    stderr.writeln("Error - Cannot read from "& filename)
    stderr.flushFile()
  minimStream(stream, filename)

proc completionCallback*(str: cstring, completions: ptr linenoiseCompletions) = 
  var words = ($str).split(" ")
  var w = words.pop
  var sep = ""
  if words.len > 0:
    sep = " "
  for s in SYMBOLS.keys:
      if startsWith(s, w):
        linenoiseAddCompletion completions, words.join(" ") & sep & s

proc minimRepl*() = 
  var i = newMinInterpreter(debugging)
  var s = newStringStream("")
  i.open(s, "")
  echo "MiNiM v"&version&" - REPL initialized."
  i.eval prelude
  echo "Prelude loaded."
  echo "-> Type 'exit' or 'quit' to exit."
  discard linenoiseSetCompletionCallback completionCallback
  var line: cstring
  while true:
    line = linenoise(": ")
    discard linenoiseHistoryAdd line
    s.writeln(line)
    i.parser.buf = $i.parser.buf & $line
    i.parser.bufLen = i.parser.buf.len
    discard i.parser.getToken() 
    try:
      i.interpret()
    except:
      warn getCurrentExceptionMsg()
    finally:
      stdout.write "-> "
      echo i.dump
    
###

var file, str: string = ""

for kind, key, val in getopt():
  case kind:
    of cmdArgument:
      file = key
    of cmdLongOption, cmdShortOption:
      case key:
        of "debug", "d":
          debugging = true
        of "evaluate", "e":
          str = val
        of "help", "h":
          echo usage
          quit(0)
        of "version", "v":
          echo version
        of "interactive", "i":
          repl = true
    else:
      discard

if str != "":
  minimString(str)
elif file != "":
  minimFile file
elif repl:
  minimRepl()
  quit(0)
else:
  minimFile stdin