feat(scope) Implemented simple lexical scoping.
h3rald h3rald@h3rald.com
Sat, 21 May 2016 12:37:31 +0200
5 files changed,
43 insertions(+),
39 deletions(-)
M
core/interpreter.nim
→
core/interpreter.nim
@@ -2,7 +2,6 @@ import streams, strutils, critbits
import types, parser, - scope, ../vendor/linenoise const ERRORS: array [MinError, string] = [@@ -17,12 +16,31 @@ "Two numbers are required on the stack",
"Division by zero" ] -var ROOT*: MinScope +var ROOT*: ref MinScope = new MinScope + +proc getSymbol*(scope: ref MinScope, key: string): MinOperator = + if scope.symbols.hasKey(key): + return scope.symbols[key] + elif not scope.parent.isNil: + return scope.parent.getSymbol(key) + +proc getSigil*(scope: ref MinScope, key: string): MinOperator = + if scope.sigils.hasKey(key): + return scope.sigils[key] + elif not scope.parent.isNil: + return scope.parent.getSigil(key) proc newMinInterpreter*(debugging = false): MinInterpreter = - var s:MinStack = newSeq[MinValue](0) - var p:MinParser - var i:MinInterpreter = MinInterpreter(filename: "input", parser: p, stack: s, debugging: debugging, currSym: MinValue(column: 1, line: 1, kind: minSymbol, symVal: "")) + var st:MinStack = newSeq[MinValue](0) + var pr:MinParser + var i:MinInterpreter = MinInterpreter( + filename: "input", + parser: pr, + stack: st, + scope: ROOT, + debugging: debugging, + currSym: MinValue(column: 1, line: 1, kind: minSymbol, symVal: "") + ) return i proc error*(i: MinInterpreter, status: MinError, message = "") =@@ -57,17 +75,19 @@ if not i.evaluating:
i.currSym = val let symbol = val.symVal let sigil = "" & symbol[0] - if ROOT.symbols.hasKey(val.symVal): + let symbolProc = i.scope.getSymbol(symbol) + if not symbolProc.isNil: try: - ROOT.symbols[val.symVal](i) + symbolProc(i) except: i.error(errSystem, getCurrentExceptionMsg()) else: - if ROOT.sigils.hasKey(sigil) and symbol.len > 1: + let sigilProc = i.scope.getSigil(sigil) + if symbol.len > 1 and not sigilProc.isNil: let sym = symbol[1..symbol.len-1] try: i.stack.add(MinValue(kind: minString, strVal: sym)) - ROOT.sigils[sigil](i) + sigilProc(i) except: i.error(errSystem, getCurrentExceptionMsg()) else:@@ -123,7 +143,7 @@ finally:
i.filename = fn proc apply*(i: var MinInterpreter, symbol: string) = - ROOT.symbols[symbol](i) + i.scope.symbols[symbol](i) proc copystack*(i: var MinInterpreter): MinStack = var s = newSeq[MinValue](0)
D
core/scope.nim
@@ -1,20 +0,0 @@
-import critbits, strutils -import - types - - -proc lookupSymbol*(scope: ref MinScope, key: string): MinOperator = - if scope.symbols.hasKey(key): - return scope.symbols[key] - elif scope.parent != nil: - return scope.parent.lookupSymbol(key) - -proc lookupSigil*(scope: ref MinScope, key: string): MinOperator = - if scope.sigils.hasKey(key): - return scope.sigils[key] - elif scope.parent != nil: - return scope.parent.lookupSigil(key) - -proc lookupLocal*(scope: ref MinScope, key: string): MinValue = - if scope.locals.hasKey(key): - return scope.locals[key]
M
core/types.nim
→
core/types.nim
@@ -20,7 +20,6 @@ minString,
minSymbol, minBool MinScope* = object - locals*: CritBitTree[MinValue] symbols*: CritBitTree[MinOperator] sigils*: CritBitTree[MinOperator] parent*: ref MinScope@@ -71,6 +70,7 @@ EMinParsingError* = ref object of ValueError
EMinUndefinedError* = ref object of ValueError MinInterpreter* = object stack*: MinStack + scope*: ref MinScope parser*: MinParser currSym*: MinValue filename*: string
M
lib/lang.nim
→
lib/lang.nim
@@ -10,13 +10,13 @@ quit(0)
minsym "symbols", i: var q = newSeq[MinValue](0) - for s in ROOT.symbols.keys: + for s in i.scope.symbols.keys: q.add s.newVal i.push q.newVal minsym "sigils", i: var q = newSeq[MinValue](0) - for s in ROOT.sigils.keys: + for s in i.scope.sigils.keys: q.add s.newVal i.push q.newVal@@ -41,9 +41,9 @@ 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 ROOT.symbols.hasKey(symbol): + if not i.scope.getSymbol(symbol).isNil: i.error errSystem, "Symbol '$1' already exists" % [symbol] - minsym symbol, i: + i.scope.symbols[symbol] = proc(i: var MinInterpreter) = i.evaluating = true i.push q1.qVal i.evaluating = false@@ -52,7 +52,7 @@ minsym "unbind", i:
var q1 = i.pop if q1.qVal.len == 1 and q1.qVal[0].kind == minSymbol: var symbol = q1.qVal[0].symVal - ROOT.symbols.excl symbol + i.scope.symbols.excl symbol else: i.error errIncorrect, "The top quotation must contain only one symbol value"@@ -68,9 +68,9 @@ if q1.isQuotation and q2.isQuotation:
if q1.qVal.len == 1 and q1.qVal[0].kind == minSymbol: var symbol = q1.qVal[0].symVal if symbol.len == 1: - if ROOT.sigils.hasKey(symbol): + if not i.scope.getSigil(symbol).isNil: i.error errSystem, "Sigil '$1' already exists" % [symbol] - minsigil symbol, i: + i.scope.sigils[symbol] = proc(i: var MinInterpreter) = i.evaluating = true i.push q2.qVal i.evaluating = false
M
lib/quotations.nim
→
lib/quotations.nim
@@ -15,8 +15,12 @@ minsym "unquote", i:
let q = i.pop if not q.isQuotation: i.error errNoQuotation + let scope = i.scope + i.scope = new MinScope + i.scope.parent = scope for item in q.qVal: - i.push item + i.push item + i.scope = scope minsym "cons", i: var q = i.pop