all repos — min @ 86c623a957aa83e3325656a760f046c15e873d70

A small but practical concatenative programming language.

refact(scope) Renamed symbols (let -> define) etc.
h3rald h3rald@h3rald.com
Fri, 03 Jun 2016 10:11:37 +0200
commit

86c623a957aa83e3325656a760f046c15e873d70

parent

c7a3e22961e0a322b4a9d75aacdcde81dec02058

5 files changed, 108 insertions(+), 76 deletions(-)

jump to
M core/interpreter.nimcore/interpreter.nim

@@ -33,29 +33,24 @@ return scope.symbols[key]

elif not scope.parent.isNil: return scope.parent.getSymbol(key) -proc delSymbol*(scope: ref MinScope, key: string) = +proc delSymbol*(scope: ref MinScope, key: string): bool {.discardable.}= #echo key, " - ", scope.symbols.hasKey(key) if scope.symbols.hasKey(key): scope.symbols.excl(key) - elif not scope.parent.isNil: - scope.parent.delSymbol(key) + return true + return false proc setSymbol*(scope: ref MinScope, key: string, value: MinOperator): bool {.discardable.}= result = false - # check if a symbol already exists in parent scope - if not scope.parent.isNil and scope.parent.symbols.hasKey(key): - scope.parent.symbols[key] = value - #echo "($1) SET EXISTING SYMBOL: $2" % [scope.parent.fullname, key] - return true + # check if a symbol already exists in current scope + if not scope.isNil and scope.symbols.hasKey(key): + scope.symbols[key] = value + #echo "($1) SET EXISTING SYMBOL: $2" % [scope.fullname, key] + result = true else: # Go up the scope chain and attempt to find the symbol if not scope.parent.isNil: result = scope.parent.setSymbol(key, value) - if not result: - # Define local variable - #echo "($1) SET LOCAL SYMBOL: $2" % [scope.fullname, key] - scope.symbols[key] = value - return true proc getSigil*(scope: ref MinScope, key: string): MinOperator = if scope.sigils.hasKey(key):
M lib/lang.nimlib/lang.nim

@@ -37,7 +37,7 @@ echo "Debugging: $1" % [$i.debugging]

# Language constructs - .symbol("let") do (i: In): + .symbol("define") do (i: In): var q2 = i.pop # new (can be a quoted symbol or a string) var q1 = i.pop # existing (auto-quoted) var symbol: string

@@ -50,7 +50,7 @@ symbol = q2.qVal[0].symVal

else: i.error errIncorrect, "The top quotation must contain only one symbol value" return - i.debug "[let] " & symbol & " = " & $q1 + i.debug "[define] " & symbol & " = " & $q1 i.scope.symbols[symbol] = proc(i: var MinInterpreter) = #i.evaluating = true #i.filename = q1.filename # filename will be reset automatically by interpreter

@@ -74,7 +74,7 @@ i.debug "[bind] " & symbol & " = " & $q1

#if not i.filename.isNil and i.filename != "eval": # echo "BIND $1 - fn: $2" % [symbol, i.filename] # q1.filename = i.filename # Save filename for diagnostic purposes - i.scope.setSymbol(symbol) do (i: In): + let res = i.scope.setSymbol(symbol) do (i: In): #i.evaluating = true let fn = i.filename #if not q1.filename.isNil:

@@ -83,12 +83,16 @@ #echo "BIND '$1' FN: $2" % [symbol, i.filename]

i.push q1.qVal #i.filename = fn #i.evaluating = false + if not res: + i.error errRuntime, "Attempting to bind undefined symbol: " & symbol .symbol("delete") do (i: In): var sym = i.pop if not sym.isStringLike: i.error errIncorrect, "A string or a symbol are required on the stack" - i.scope.delSymbol(sym.getString) + let res = i.scope.delSymbol(sym.getString) + if not res: + i.error errRuntime, "Attempting to delete undefined symbol: " & sym.getString .symbol("module") do (i: In): let name = i.pop

@@ -168,43 +172,74 @@ i.error(errIncorrect, "A string is required on the stack")

.symbol("call") do (i: In): - let fqn = i.pop - if fqn.isQuotation: - let vals = fqn.qVal - var q: MinValue - if vals.len == 0: - i.error(errIncorrect, "No symbol to call") + let symbols = i.pop + if not symbols.isQuotation: + i.error(errIncorrect, "A quotation is required on the stack") + let vals = symbols.qVal + var q: MinValue + if vals.len == 0: + i.error errIncorrect, "No symbol to call" + return + let origScope = i.scope + for c in 0..vals.len-1: + if not vals[c].isStringLike: + i.error(errIncorrect, "Quotation must contain only symbols or strings") + return + let symbol = vals[c].getString + let qProc = i.scope.getSymbol(symbol) + if qProc.isNil: + i.error(errUndefined, "Symbol '$1' not found in scope '$2'" % [symbol, i.scope.fullname]) return - var symScope = i.scope - var symFilename = i.filename - for c in 0..vals.len-1: - if not vals[c].isStringLike: - i.error(errIncorrect, "Quotation must contain only symbols or strings") + qProc(i) + if vals.len > 1 and c < vals.len-1: + q = i.pop + if not q.isQuotation: + i.error(errIncorrect, "Unable to evaluate symbol '$1'" % [symbol]) return - let qProc = i.scope.getSymbol(vals[c].getString) - if qProc.isNil: - i.error(errUndefined, "Symbol '$1' not found" % [vals[c].getString]) - return - let currScope = i.scope - let currFilename = i.filename - # Execute operator in "parent" symbol scope - #echo "CALL - executing '$1' fn: $2" % [vals[c].getString, "-"] - i.scope = symScope - #i.filename = symFilename - #echo ">>> CALL: ", vals[c].getString, " - ", symFilename - qProc(i) - i.scope = currScope - #echo "<<< CALL: ", currFilename - #i.filename = currFilename - if vals.len > 1 and c < vals.len-1: - q = i.pop - if not q.isQuotation: - i.error(errIncorrect, "Unable to evaluate symbol '$1'" % [vals[c-1].getString]) - return - symScope = q.scope - symFilename = q.filename - else: - i.error(errIncorrect, "A quotation is required on the stack") + i.scope = q.scope + i.scope = origScope + + + + +# .symbol("call") do (i: In): +# let fqn = i.pop +# if fqn.isQuotation: +# let vals = fqn.qVal +# var q: MinValue +# if vals.len == 0: +# i.error(errIncorrect, "No symbol to call") +# return +# var symScope = i.scope +# var symFilename = i.filename +# for c in 0..vals.len-1: +# if not vals[c].isStringLike: +# i.error(errIncorrect, "Quotation must contain only symbols or strings") +# return +# let qProc = i.scope.getSymbol(vals[c].getString) +# if qProc.isNil: +# i.error(errUndefined, "Symbol '$1' not found in scope '$2'" % [vals[c].getString, i.scope.fullname]) +# return +# let currScope = i.scope +# let currFilename = i.filename +# # Execute operator in "parent" symbol scope +# #echo "CALL - executing '$1' fn: $2" % [vals[c].getString, "-"] +# i.scope = symScope +# #i.filename = symFilename +# #echo ">>> CALL: ", vals[c].getString, " - ", symFilename +# qProc(i) +# i.scope = currScope +# #echo "<<< CALL: ", currFilename +# #i.filename = currFilename +# if vals.len > 1 and c < vals.len-1: +# q = i.pop +# if not q.isQuotation: +# i.error(errIncorrect, "Unable to evaluate symbol '$1'" % [vals[c-1].getString]) +# return +# symScope = q.scope +# symFilename = q.filename +# else: +# i.error(errIncorrect, "A quotation is required on the stack") # Operations on the whole stack
M lib/prelude.minlib/prelude.min

@@ -10,8 +10,8 @@ #sys

#time ; Common sigils -(bind) (:) sigil -(let) (.) sigil +(bind) (.) sigil +(define) (:) sigil (delete) (~) sigil (getenv) ($) sigil (system) (!) sigil

@@ -21,8 +21,8 @@ (load) (@) sigil

(":" split call) (%) sigil ; Aliases -'bind :: -'let :. +'define :: +'bind :. 'module := 'import :# 'exit :quit

@@ -71,6 +71,6 @@ ((() cons cons) dip swap i) :bury2

((() cons cons cons) dip swap i) :bury3 ; Other -(print pop) :print! +(print pop) :print! (put pop) :put!
M tests/lang.mintests/lang.min

@@ -9,14 +9,16 @@ (sigils size 11 ==) assert

(debug? false ==) assert - (2 'a let - (3 a + (5 'a let a) -> +) -> a + 12 ==) assert + (2 'a define + (3 a + (5 'a define a) -> +) -> a + 12 ==) assert (symbols "a" contains false ==) assert - - (5 'five : symbols "five" contains) assert - - ("five" delete symbols "five" contains false ==) assert + + 5 :five + (symbols "five" contains) assert + + ~five + (symbols "five" contains false ==) assert ( (

@@ -69,8 +71,8 @@

((2 3 >) ("YES") ("NO") ifte "NO" ==) assert ((2 3 <) ("YES") ("NO") ifte "YES" ==) assert - (0 .c - (c 10 <) (c succ :c) while + (0 :c + (c 10 <) (c succ .c) while c 10 ==) assert ((1 2 3 4 5) (even?) filter (2 4) ==) assert
M tests/test.mintests/test.min

@@ -1,11 +1,11 @@

;; test module ( - 'OK ' .ok - (" " print!) .padding + 'OK ' :ok + (" " print!) :padding ;; describe ( - .name + :name "Testing: [" print! name print! "]" put! padding ()

@@ -13,8 +13,8 @@ ) :describe

;; assert ( - ' .check ; save the check quotation to validate - ' .results ; save the result symbol to update + ' :check ; save the check quotation to validate + ' :results ; save the result symbol to update (check -> true ==) ( ok results append quote :results

@@ -31,16 +31,16 @@

;; report ( newline - ' .results ; save the results collected so far - 0 .total - 0 .failed + ' :results ; save the results collected so far + 0 :total + 0 :failed results ( - total succ :total - (ok !=) (failed succ :failed) () ifte + total succ .total + (ok !=) (failed succ .failed) () ifte ) map padding total print! " tests executed - " print! failed print! " failed." put! ( - ' .result + ' :result result (ok !=) (padding "FAILED: " print! result put!)