all repos — min @ d9cc6bedab9a454ca1b4cf5fd0a3d54b3ec5af88

A small but practical concatenative programming language.

Implementing proper support for dotted symbol (tests failing)
h3rald h3rald@h3rald.com
Sat, 25 May 2024 15:17:38 +0200
commit

d9cc6bedab9a454ca1b4cf5fd0a3d54b3ec5af88

parent

ea5a95db538fb57d6e05c6613e6a09f434d2310f

M min.nimmin.nim

@@ -209,9 +209,8 @@ customPrelude = val

of "dev", "d": DEV = true of "log", "l": - if file == "": - var val = val - niftylogger.setLogLevel(val) + var v = val + niftylogger.setLogLevel(v) of "passN", "n": NIMOPTIONS = val of "help", "h":
M minpkg/core/interpreter.nimminpkg/core/interpreter.nim

@@ -29,6 +29,7 @@ var COMPILEDASSETS* {.threadvar.}: CritBitTree[string]

var CACHEDMODULES* {.threadvar.}: CritBitTree[MinValue] const USER_SYMBOL_REGEX* = "^[a-zA-Z_][a-zA-Z0-9/!?+*_-]*$" +const USER_PATH_SYMBOL_REGEX* = "^[a-zA-Z_][a-zA-Z0-9/.!?+*_-]*$" proc diff*(a, b: seq[MinValue]): seq[MinValue] = result = newSeq[MinValue](0)

@@ -251,80 +252,6 @@ column: i.currSym.column,

outerSym: i.currSym.symVal, docComment: i.currSym.docComment) -proc getSymbolPath*(i: In, symbol: string) = - let parts = symbol.split(".") - if parts.len < 2: - raiseInvalid("Dictionary identifier not specified") - i.pushSym parts[0] - for p in 0..parts.len-2: - let mdl = i.pop - if mdl.kind != minDictionary: - raiseInvalid("$1 is not a dictionary" % [mdl.getString]) - let symId = parts[p+1] - let origScope = i.scope - i.scope = mdl.scope - if not i.scope.parent.isNil: - i.scope.parent = origScope - let sym = i.scope.getSymbol(symId) - i.apply(sym) - i.scope = origScope - -proc setSymbolPath*(i: In, symbol: string, q1: MinValue, mustExist: bool) = - let parts = symbol.split(".") - if parts.len < 2: - raiseInvalid("Dictionary identifier not specified") - i.pushSym parts[0] - var count = 0 - for p in 0..parts.len-2: - let mdl = i.pop - if mdl.kind != minDictionary: - raiseInvalid("$1 is not a dictionary" % [mdl.getString]) - let symId = parts[p+1] - let origScope = i.scope - i.scope = mdl.scope - if not i.scope.parent.isNil: - i.scope.parent = origScope - var sym: MinOperator - var notFound = false - try: - sym = i.scope.getSymbol(symId) - except CatchableError: - notFound = true - discard - if (notFound and mustExist): - raiseInvalid("Symbol $# does not exist" % [symId]) - if count >= parts.len-2: - if not symId.contains re(USER_SYMBOL_REGEX): - raiseInvalid("Symbol identifier '$1' contains invalid characters." % symId) - info "[define] $1 = $2" % [symbol, $q1] - if mdl.scope.symbols.hasKey(symId) and mdl.scope.symbols[symId].sealed: - raiseUndefined("Attempting to redefine sealed symbol '$1'" % [symbol]) - mdl.scope.symbols[symId] = MinOperator(kind: minValOp, val: q1, - sealed: false, quotation: q1.isQuotation) - i.scope = origScope - count = count+1 - -proc getSymbolObjectPath*(i: In, symbol: string): MinOperator = - let parts = symbol.split(".") - if parts.len < 2: - raiseInvalid("Dictionary identifier not specified") - i.pushSym parts[0] - var count = 0 - for p in 0..parts.len-2: - let mdl = i.pop - if mdl.kind != minDictionary: - raiseInvalid("$1 is not a dictionary" % [mdl.getString]) - let symId = parts[p+1] - let origScope = i.scope - i.scope = mdl.scope - if not i.scope.parent.isNil: - i.scope.parent = origScope - result = i.scope.getSymbol(symId) - if count < parts.len-2: - i.apply(result) - i.scope = origScope - count = count+1 - proc push*(i: In, val: MinValue) = if val.kind == minSymbol: i.debug(val)

@@ -340,11 +267,8 @@ raise MinReturnException(msg: "return symbol found")

if i.scope.hasSymbol(symbol): i.apply i.scope.getSymbol(symbol), symbol else: - # Process dictionary access - if symbol.contains('.'): - i.getSymbolPath(symbol) # Check if symbol ends with ! (auto-popping) - elif symbol.len > 1 and symbol[symbol.len-1] == '!': + if symbol.len > 1 and symbol[symbol.len-1] == '!': let apSymbol = symbol[0..symbol.len-2] if i.scope.hasSymbol(apSymbol): i.apply i.scope.getSymbol(apSymbol)
M minpkg/core/niftylogger.nimminpkg/core/niftylogger.nim

@@ -74,5 +74,5 @@ lvl = lvlNone

else: val = "warn" lvl = lvlWarn - setLogFilter(lvl) + logging.setLogFilter(lvl) return val
M minpkg/core/scope.nimminpkg/core/scope.nim

@@ -11,6 +11,10 @@ scope.sigils = s.sigils

new(result) result[] = scope +proc isQuotedDictionary(d: MinOperator): bool = + return d.kind == minValOp and d.val.kind == minQuotation and d.val.qVal.len == + 1 and d.val.qVal[0].kind == minDictionary + proc getSymbolFromPath(scope: ref MinScope, keys: var seq[ string], acc = 0): MinOperator

@@ -27,13 +31,14 @@ return scope.parent.getSymbol(key, acc + 1)

proc getSymbolFromPath(scope: ref MinScope, keys: var seq[ string], acc = 0): MinOperator = - let sym = keys.pop + let sym = keys[0] + keys.delete(0) let d = scope.getSymbol(sym, acc) - if d.kind == minValOp and d.val.kind == minDictionary: - if keys.len > 2: - return d.val.scope.getSymbolFromPath(keys, acc + 1) + if d.isQuotedDictionary: + if keys.len > 1: + return d.val.qVal[0].scope.getSymbolFromPath(keys, acc + 1) else: - return d.val.scope.getSymbol(keys[1], acc + 1) + return d.val.qVal[0].scope.getSymbol(keys[0], acc + 1) else: raiseInvalid("Symbol '$1' is not a dictionary." % sym)

@@ -55,13 +60,14 @@ return false

proc hasSymbolFromPath(scope: ref MinScope, keys: var seq[ string]): bool = - let sym = keys.pop + let sym = keys[0] + keys.delete(0) let d = scope.getSymbol(sym) - if d.kind == minValOp and d.val.kind == minDictionary: - if keys.len > 2: - return d.val.scope.hasSymbolFromPath(keys) + if d.isQuotedDictionary: + if keys.len > 1: + return d.val.qVal[0].scope.hasSymbolFromPath(keys) else: - return d.val.scope.hasSymbol(keys[1]) + return d.val.qVal[0].scope.hasSymbol(keys[0]) else: raiseInvalid("Symbol '$1' is not a dictionary." % sym)

@@ -81,13 +87,14 @@ return false

proc delSymbolFromPath(scope: ref MinScope, keys: var seq[ string]): bool = - let sym = keys.pop + let sym = keys[0] + keys.delete(0) let d = scope.getSymbol(sym) - if d.kind == minValOp and d.val.kind == minDictionary: - if keys.len > 2: - return d.val.scope.delSymbolFromPath(keys) + if d.isQuotedDictionary: + if keys.len > 1: + return d.val.qVal[0].scope.delSymbolFromPath(keys) else: - return d.val.scope.delSymbol(keys[1]) + return d.val.qVal[0].scope.delSymbol(keys[0]) else: raiseInvalid("Symbol '$1' is not a dictionary." % sym)

@@ -95,7 +102,7 @@ proc setSymbolFromPath(scope: ref MinScope, keys: var seq[

string], value: MinOperator, override = false): bool {.discardable.} proc setSymbol*(scope: ref MinScope, key: string, value: MinOperator, - override = false): bool {.discardable.} = + override = false, define = false): bool {.discardable.} = result = false if key.contains ".": var keys = key.split(".")

@@ -106,6 +113,10 @@ if not override and scope.symbols[key].sealed:

raiseInvalid("Symbol '$1' is sealed ." % key) scope.symbols[key] = value result = true + # define new symbol + elif not scope.isNil and define: + scope.symbols[key] = value + result = true else: # Go up the scope chain and attempt to find the symbol if not scope.parent.isNil:

@@ -113,13 +124,14 @@ result = scope.parent.setSymbol(key, value, override)

proc setSymbolFromPath(scope: ref MinScope, keys: var seq[ string], value: MinOperator, override = false): bool {.discardable.} = - let sym = keys.pop + let sym = keys[0] + keys.delete(0) let d = scope.getSymbol(sym) - if d.kind == minValOp and d.val.kind == minDictionary: - if keys.len > 2: - return d.val.scope.setSymbolFromPath(keys, value, override) + if d.isQuotedDictionary: + if keys.len > 1: + return d.val.qVal[0].scope.setSymbolFromPath(keys, value, override) else: - return d.val.scope.setSymbol(keys[1], value, override) + return d.val.qVal[0].scope.setSymbol(keys[0], value, override) else: raiseInvalid("Symbol '$1' is not a dictionary." % sym)
M minpkg/core/stdlib.nimminpkg/core/stdlib.nim

@@ -34,7 +34,6 @@ var customPrelude* {.threadvar.}: string

customPrelude = "" proc stdLib*(i: In) = - setLogFilter(logging.lvlNotice) if not MINSYMBOLS.fileExists: MINSYMBOLS.writeFile("{}") if not MINHISTORY.fileExists:
M minpkg/lib/min_global.nimminpkg/lib/min_global.nim

@@ -508,16 +508,11 @@ var q1 = vals[1] # existing (auto-quoted)

var symbol: string q1 = @[q1].newVal symbol = sym.getString - if symbol.contains ".": - i.setSymbolPath(symbol, q1, false) - return - if not symbol.contains re(USER_SYMBOL_REGEX): + if not symbol.contains re(USER_PATH_SYMBOL_REGEX): raiseInvalid("Symbol identifier '$1' contains invalid characters." % symbol) info "[define] $1 = $2" % [symbol, $q1] - if i.scope.symbols.hasKey(symbol) and i.scope.symbols[symbol].sealed: - raiseUndefined("Attempting to redefine sealed symbol '$1'" % [symbol]) - i.scope.symbols[symbol] = MinOperator(kind: minValOp, val: q1, - sealed: false, quotation: q1.isQuotation) + i.scope.setSymbol(symbol, MinOperator(kind: minValOp, val: q1, + sealed: false, quotation: q1.isQuotation), false, true) def.symbol("typealias") do (i: In): let vals = i.expect("'sym", "'sym")

@@ -556,9 +551,6 @@ var symbol: string

var isQuot = q1.isQuotation q1 = @[q1].newVal symbol = sym.getString - if symbol.contains ".": - i.setSymbolPath(symbol, q1, true) - return info "[bind] $1 = $2" % [symbol, $q1] let res = i.scope.setSymbol(symbol, MinOperator(kind: minValOp, val: q1, quotation: isQuot))