all repos — min @ 6d9717124714f473da9c798a10a17cf3cea4fc27

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
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
import streams, tables, parseopt2, strutils
import 
  core/parser, 
  core/interpreter, 
  core/utils
import 
  lib/lang, 
  lib/stack, 
  lib/quotations,
  lib/numbers,
  lib/strings,
  lib/logic,
  lib/time, 
  lib/io,
  lib/sys

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

const
  USE_LINENOISE = false #(defined(i386) or defined(amd64))# and not defined(windows)


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 Eval Print Loop"""

when USE_LINENOISE:
  import vendor/linenoise
  proc completionCallback*(str: cstring, completions: ptr linenoiseCompletions) = 
    var words = ($str).split(" ")
    var w = if words.len > 0: words.pop else: ""
    var sep = ""
    if words.len > 0:
      sep = " "
    for s in SYMBOLS.keys:
      if startsWith(s, w):
        linenoiseAddCompletion completions, words.join(" ") & sep & s
  proc prompt(s: string): string = 
    var res = linenoise(s)
    discard $linenoiseHistoryAdd(res)
    return $res
else:
  proc prompt(s: string): string = 
    stdout.write(s)
    return stdin.readLine

proc minimStream(s: Stream, 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.writeLine("Error - Cannot read from file: "& filename)
    stderr.flushFile()
  minimStream(stream, filename)

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

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."
  #if USE_LINENOISE:
  #  discard linenoiseSetCompletionCallback completionCallback
  var line: string
  while true:
    line = prompt(": ")
    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
    else:
      discard

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