all repos — min @ f2cdbd8a021bb4ef94343804db4af625e358d360

A small but practical concatenative programming language.

Added POC on loading dynamic libraries to extend min
Peter Munch-Ellingsen peterme@peterme.net
Tue, 24 Oct 2017 12:59:18 +0200
commit

f2cdbd8a021bb4ef94343804db4af625e358d360

parent

19afd6c88ca389d12a7eb058495860a6c519feb8

4 files changed, 242 insertions(+), 1 deletions(-)

jump to
A dyntest.min

@@ -0,0 +1,5 @@

+'dyn import +1 1 + +1 1 myplus +== +puts!
M min.nimmin.nim

@@ -7,7 +7,9 @@ os,

json, sequtils, algorithm, - logging + logging, + dynlib + import packages/nimline/nimline, packages/niftylogger,

@@ -130,8 +132,43 @@ i.eval PRELUDE, "<prelude>"

i.eval MINRC.readFile() i.eval "\"prompt\" unseal" +type + setupProc = proc( + defineProc: proc(i: In): ref MinScope, + finalizeProc: proc(scope: ref MinScope, name: string), + symbolProc: proc(scope: ref MinScope, sym: string, p: MinOperatorProc), + expectProc: proc(i: var MinInterpreter, elements: varargs[string]): seq[MinValue], + pushProc: proc(i: In, val: MinValue) + ): string {.nimcall.} + libProc = proc( + i: In + ) {.nimcall.} +proc dynLib*(i: In) = + var + dll: LibHandle + setup: setupProc + dll = loadLib("./dynlibs/libmindyn.so") + if dll != nil: + let setupAddr = dll.symAddr("setup") + if setupAddr != nil: + setup = cast[setupProc](setupAddr) + + if setup != nil: + let + libName = setup(define, finalize, symbol, expect, push) + libAddr = dll.symAddr(libName) + if libAddr != nil: + var lib = cast[libProc](libAddr) + i.lib + echo "Loaded dynlib" + else: + echo "Wasn't able to load " & libName & "(i: In) from DLL." + else: + echo "Wasn't able to load setup() from DLL." + proc interpret*(i: In, s: Stream) = i.stdLib() + i.dynLib() i.open(s, i.filename) discard i.parser.getToken() try:

@@ -177,6 +214,7 @@ echo "{$1} -> $2" % [$i.stack.len, $i.stack[i.stack.len - 1]]

proc minRepl*(i: var MinInterpreter) = i.stdLib() + i.dynLib() var s = newStringStream("") i.open(s, "<repl>") var line: string
A mindyn.nim

@@ -0,0 +1,198 @@

+{.pragma: rtl, exportc, dynlib, cdecl.} + +import + lexbase, + streams, + critbits + +type + MinTokenKind* = enum + tkError, + tkEof, + tkString, + tkInt, + tkFloat, + tkBracketLe, + tkBracketRi, + tkSymbol, + tkTrue, + tkFalse + MinKind* = enum + minInt, + minFloat, + minQuotation, + minString, + minSymbol, + minBool + MinEventKind* = enum ## enumeration of all events that may occur when parsing + eMinError, ## an error ocurred during parsing + eMinEof, ## end of file reached + eMinString, ## a string literal + eMinInt, ## an integer literal + eMinFloat, ## a float literal + eMinQuotationStart, ## start of an array: the ``(`` token + eMinQuotationEnd ## start of an array: the ``)`` token + MinParserError* = enum ## enumeration that lists all errors that can occur + errNone, ## no error + errInvalidToken, ## invalid token + errStringExpected, ## string expected + errBracketRiExpected, ## ``)`` expected + errQuoteExpected, ## ``"`` or ``'`` expected + errEOC_Expected, ## ``*/`` expected + errEofExpected, ## EOF expected + errExprExpected + MinParserState* = enum + stateEof, + stateStart, + stateQuotation, + stateExpectValue + MinParser* = object of BaseLexer + a*: string + token*: MinTokenKind + state*: seq[MinParserState] + kind*: MinEventKind + err*: MinParserError + filename*: string + MinValue* = ref MinValueObject + MinValueObject* = object + line*: int + column*: int + filename*: string + case kind*: MinKind + of minInt: intVal*: BiggestInt + of minFloat: floatVal*: BiggestFloat + of minQuotation: + qVal*: seq[MinValue] + scope*: ref MinScope + of minString: strVal*: string + of minSymbol: symVal*: string + of minBool: boolVal*: bool + MinScope* = object + symbols*: CritBitTree[MinOperator] + sigils*: CritBitTree[MinOperator] + parent*: ref MinScope + name*: string + stack*: MinStack + MinOperatorProc* = proc (i: In) {.closure.} + MinOperatorKind* = enum + minProcOp + minValOp + MinOperator* = object + sealed*: bool + case kind*: MinOperatorKind + of minProcOp: + prc*: MinOperatorProc + of minValOp: + val*: MinValue + MinStack* = seq[MinValue] + In* = var MinInterpreter + MinInterpreter* = object + stack*: MinStack + trace*: MinStack + stackcopy*: MinStack + pwd*: string + scope*: ref MinScope + parser*: MinParser + currSym*: MinValue + filename*: string + evaluating*: bool + MinParsingError* = ref object of ValueError + MinUndefinedError* = ref object of ValueError + MinEmptyStackError* = ref object of ValueError + MinInvalidError* = ref object of ValueError + MinOutOfBoundsError* = ref object of ValueError + +proc isSymbol*(s: MinValue): bool = + return s.kind == minSymbol + +proc isQuotation*(s: MinValue): bool = + return s.kind == minQuotation + +proc isString*(s: MinValue): bool = + return s.kind == minString + +proc isFloat*(s: MinValue): bool = + return s.kind == minFloat + +proc isInt*(s: MinValue): bool = + return s.kind == minInt + +proc isNumber*(s: MinValue): bool = + return s.kind == minInt or s.kind == minFloat + +proc isBool*(s: MinValue): bool = + return s.kind == minBool + +proc isStringLike*(s: MinValue): bool = + return s.isSymbol or s.isString or (s.isQuotation and s.qVal.len == 1 and s.qVal[0].isSymbol) + +proc isDictionary*(q: MinValue): bool = + if not q.isQuotation: + return false + if q.qVal.len == 0: + return true + for val in q.qVal: + if not val.isQuotation or val.qVal.len != 2 or not val.qVal[0].isString: + return false + return true + +proc newVal*(s: string): MinValue = + return MinValue(kind: minString, strVal: s) + +proc newVal*(s: cstring): MinValue = + return MinValue(kind: minString, strVal: $s) + +#proc newVal*(q: seq[MinValue], parentScope: ref MinScope): MinValue = +# return MinValue(kind: minQuotation, qVal: q, scope: newScopeRef(parentScope)) + +proc newVal*(s: BiggestInt): MinValue = + return MinValue(kind: minInt, intVal: s) + +proc newVal*(s: BiggestFloat): MinValue = + return MinValue(kind: minFloat, floatVal: s) + +proc newVal*(s: bool): MinValue = + return MinValue(kind: minBool, boolVal: s) + +proc newSym*(s: string): MinValue = + return MinValue(kind: minSymbol, symVal: s) + +var + define: proc(i: In): ref MinScope + finalize: proc(scope: ref MinScope, name: string) + symbol: proc(scope: ref MinScope, sym: string, p: MinOperatorProc) + expect: proc(i: var MinInterpreter, elements: varargs[string]): seq[MinValue] + push: proc(i: In, val: MinValue) + +proc setup*( + defineProc: proc(i: In): ref MinScope, + finalizeProc: proc(scope: ref MinScope, name: string), + symbolProc: proc(scope: ref MinScope, sym: string, p: MinOperatorProc), + expectProc: proc(i: var MinInterpreter, elements: varargs[string]): seq[MinValue], + pushProc: proc(i: In, val: MinValue) + ): string {.rtl.} = + echo "Hello from lib" + define = defineProc + finalize = finalizeProc + symbol = symbolProc + expect = expectProc + push = pushProc + result = "the_lib" + +proc the_lib*(i: In) {.rtl.} = + let def = i.define() + def.symbol("myplus") do (i: In): + let vals = i.expect("num", "num") + let a = vals[0] + let b = vals[1] + if a.isInt: + if b.isInt: + i.push newVal(a.intVal + b.intVal) + else: + i.push newVal(a.intVal.float + b.floatVal) + else: + if b.isFloat: + i.push newVal(a.floatVal + b.floatVal) + else: + i.push newVal(a.floatVal + b.intVal.float) + def.finalize("dyn")