all repos — min @ a0894a184e135b97649ee65977582137a9f20008

A small but practical concatenative programming language.

Refactoring, symbols can now be updated if necessary.
h3rald h3rald@h3rald.com
Sun, 14 Dec 2014 19:39:43 +0100
commit

a0894a184e135b97649ee65977582137a9f20008

parent

38f9676ebfb1e81a574ec7fbabfe106e276a59e0

M core/interpreter.nimcore/interpreter.nim

@@ -35,8 +35,8 @@ "Two numbers are required on the stack",

"Division by zero" ] -var SYMBOLS* = initOrderedTable[string, TMinOperator]() -var SIGILS* = initOrderedTable[string, TMinOperator]() +var SYMBOLS* = initTable[string, TMinOperator]() +var SIGILS* = initTable[string, TMinOperator]() proc newMinInterpreter*(debugging = false): TMinInterpreter = var s:TMinStack = newSeq[TMinValue](0)

@@ -143,3 +143,11 @@ i.filename = fn

proc apply*(i: var TMinInterpreter, symbol: string) = SYMBOLS[symbol](i) + +proc copystack*(i: var TMinInterpreter): TMinStack = + var s = newSeq[TMinValue](0) + for i in i.stack: + s.add i + return s + +
M core/utils.nimcore/utils.nim

@@ -1,21 +1,13 @@

import tables, strutils import parser, interpreter -proc sortSymbols() = - SYMBOLS.sort(proc (a, b):int = return a.key.cmpIgnoreCase(b.key)) - -proc sortSigils() = - SIGILS.sort(proc (a, b):int = return a.key.cmpIgnoreCase(b.key)) - template minsym*(name: string, body: stmt): stmt {.immediate.} = SYMBOLS[name] = proc (i: var TMinInterpreter) = body - sortSymbols() template minsigil*(name: char, body: stmt): stmt {.immediate.} = SIGILS[name] = proc (i: var TMinInterpreter) = body - sortSigils() proc isSymbol*(s: TMinValue): bool = return s.kind == minSymbol
M lib/lang.nimlib/lang.nim

@@ -10,6 +10,12 @@ for s in SYMBOLS.keys:

q.add s.newVal i.push q.newVal +minsym "sigils": + var q = newSeq[TMinValue](0) + for s in SIGILS.keys: + q.add s.newVal + i.push q.newVal + minsym "debug?": i.push i.debugging.newVal

@@ -19,23 +25,35 @@ echo "Debugging: $1" % [$i.debugging]

# Language constructs -minsym "symbol": - var q1 = i.pop - var q2 = i.pop +minsym "bind": + var q2 = i.pop # new (can be a quoted symbol or a string) + var q1 = i.pop # existing (auto-quoted) + var symbol: string if not q1.isQuotation: q1 = @[q1].newVal - if not q2.isQuotation: - q2 = @[q2].newVal + if q2.isString: + symbol = q2.strVal + elif q2.isQuotation and q2.qVal.len == 1 and q2.qVal[0].kind == minSymbol: + symbol = q2.qVal[0].symVal + else: + i.error errIncorrect, "The top quotation must contain only one symbol value" + if SYMBOLS.hasKey(symbol): + i.error errSystem, "Symbol '$1' already exists" % [symbol] + minsym symbol: + i.evaluating = true + i.push q1.qVal + i.evaluating = false + +minsym "unbind": + var q1 = i.pop if q1.qVal.len == 1 and q1.qVal[0].kind == minSymbol: var symbol = q1.qVal[0].symVal - if SYMBOLS.hasKey(symbol): - i.error errSystem, "Symbol '$1' already exists" % [symbol] - minsym symbol: - i.evaluating = true - i.push q2.qVal - i.evaluating = false + SYMBOLS.del symbol else: i.error errIncorrect, "The top quotation must contain only one symbol value" + +minsigil "'": + i.push(@[TMinValue(kind: minSymbol, symVal: i.pop.strVal)].newVal) minsym "sigil": var q1 = i.pop

@@ -118,15 +136,3 @@ elif q.isString:

i.push newVal(q.strVal[1..q.strVal.len-1]) else: i.error(errIncorrect, "A quotation or a string is required on the stack") - -# Operations on strings - - -minsym "split": - let sep = i.pop - let s = i.pop - if s.isString and sep.isString: - for e in s.strVal.split(sep.strVal): - i.push e.newVal - else: - i.error errIncorrect, "Two strings are required on the stack"
M lib/logic.nimlib/logic.nim

@@ -120,3 +120,38 @@ i.push newVal(a.boolVal xor b.boolVal)

else: i.error(errIncorrect, "Two bool values are required on the stack") +minsym "string?": + if i.peek.kind == minString: + i.push true.newVal + else: + i.push false.newVal + +minsym "int?": + if i.peek.kind == minInt: + i.push true.newVal + else: + i.push false.newVal + +minsym "float?": + if i.peek.kind == minFloat: + i.push true.newVal + else: + i.push false.newVal + +minsym "number?": + if i.peek.kind == minFloat or i.peek.kind == minInt: + i.push true.newVal + else: + i.push false.newVal + +minsym "bool?": + if i.peek.kind == minBool: + i.push true.newVal + else: + i.push false.newVal + +minsym "quotation?": + if i.peek.kind == minQuotation: + i.push true.newVal + else: + i.push false.newVal
M lib/prelude.minlib/prelude.min

@@ -1,72 +1,58 @@

-// Aliases -[symbol] [:] symbol -[exit] [quit] : -[concat] [,] : -[print] [%] : -[==] [eq] : -[!=] [noteq] : -[>] [gt] : -[<] [lt] : -[>=] [gte] : -[<=] [lte] : -[puts] [echo] : -[system] [!] : -[run] [&] : -[getenv] [$] : -[pop] [zap] : -[quote] [unit] : -[unquote] [i] : -[unquote] [apply] : -[filter] [select] : -[clear] [empty] : -[match] [~] : -["."] [.] : -[".."] [..] : - -// Common Environment Variables -[os "windows" ==] - [ - ["HOMEPATH" $] [$HOME] : - ["USERNAME" $] [$USER] : - ] - [ - ["HOME" $] [$HOME] : - ["USER" $] [$USER] : - ] -ifte - -["PATH" $] [$PATH] : -[$HOME] [$HOMEPATH] : -[$USER] [$USERNAME] : - // Common sigils -[quote [eval] concat] ['] sigil // 'test -> [test] -[getenv] [$] sigil -[:] [:] sigil -[!] [!] sigil -[&] [&] sigil +[bind] [:] sigil +[getenv] [$] sigil +[system] [!] sigil +[run] [&] sigil + +// Aliases +'bind :: +'exit :quit +'concat :, +'print :% +'== :eq +'!= :noteq +'> :gt +'< :lt +'>= :gte +'<= :lte +'puts :echo +'system :! +'run :& +'getenv :$ +'pop :zap +'quote :unit +'unquote :i +'unquote :apply +'filter :select +'clear :empty +'match :~ +["."] :. +[".."] :.. // Mathematical Operators -[1 +] [succ] : -[1 -] [pred] : -[2 mod 0 ==] [even?] : -[even? not] [odd?] : +[1 +] :succ +[1 -] :pred +[2 mod 0 ==] :even? +[even? not] :odd? -[[dup 0 ==] [1 +] [dup 1 -] [ * ] linrec] [factorial] : +[[dup 0 ==] [1 +] [dup 1 -] [ * ] linrec] :factorial // Stack Operators -[swap cons] [swons] : -[[pop] dip] [popd] : -[[dup] dip] [dupd] : -[[swap] dip] [swapd] : -[[dup] dip i] [q] : -[[zap] dip i] [k] : -[[cons] dip i] [b] : -[[swap] dip i] [c] : -[[dip] cons cons] [take] : -[[] cons dip] [dig1] : -[[] cons cons dip] [dig2] : -[[] cons cons cons dip] [dig3] : -[[[] cons] dip swap i] [bury1] : -[[[] cons cons] dip swap i] [bury2] : -[[[] cons cons cons] dip swap i] [bury3] : +[swap cons] :swons +[[pop] dip] :popd +[[dup] dip] :dupd +[[swap] dip] :swapd +[[dup] dip i] :q +[[zap] dip i] :k +[[cons] dip i] :b +[[swap] dip i] :c +[[dip] cons cons] :take +[[] cons dip] :dig1 +[[] cons cons dip] :dig2 +[[] cons cons cons dip] :dig3 +[[[] cons] dip swap i] :bury1 +[[[] cons cons] dip swap i] :bury2 +[[[] cons cons cons] dip swap i] :bury3 + +// Other +[dup unbind bind] :rebind
M lib/quotations.nimlib/quotations.nim

@@ -58,9 +58,11 @@ minsym "ifte":

let fpath = i.pop let tpath = i.pop let check = i.pop + var stack = i.copystack if check.isQuotation and tpath.isQuotation and fpath.isQuotation: i.push check.qVal let res = i.pop + i.stack = stack if res.isBool and res.boolVal == true: i.push tpath.qVal else:
M lib/regex.nimlib/strings.nim

@@ -1,6 +1,15 @@

-import tables +import tables, strutils import ../core/parser, ../core/interpreter, ../core/utils import ../vendor/slre + +minsym "split": + let sep = i.pop + let s = i.pop + if s.isString and sep.isString: + for e in s.strVal.split(sep.strVal): + i.push e.newVal + else: + i.error errIncorrect, "Two strings are required on the stack" minsym "match": let reg = i.pop

@@ -26,7 +35,7 @@ i.push false.newVal

else: i.error(errIncorrect, "Two strings are required on the stack") -minsym "gsub": +minsym "replace": let s_replace = i.pop let reg = i.pop let s_find = i.pop
M minim.nimminim.nim

@@ -8,11 +8,11 @@ lib/lang,

lib/stack, lib/quotations, lib/numbers, + lib/strings, lib/logic, lib/time, lib/io, - lib/sys, - lib/regex + lib/sys const version* = "0.1.0" var debugging = false