all repos — min @ 1ee08fd0de6b063d5bb0db373ed3abdbd2d0f307

A small but practical concatenative programming language.

No longer adding scopes to quotations while parsing.
h3rald h3rald@h3rald.com
Sat, 07 Jul 2018 12:42:18 +0200
commit

1ee08fd0de6b063d5bb0db373ed3abdbd2d0f307

parent

1a4c94a42628112fe606a8787a76939bc8728a51

M core/interpreter.nimcore/interpreter.nim

@@ -32,23 +32,30 @@

proc debug*(i: In, value: string) {.extern:"min_exported_symbol_$1_2".}= debug(value) -template withScope*(i: In, q: MinValue, res:ref MinScope, body: untyped): untyped = +template withScope*(i: In, res:ref MinScope, body: untyped): untyped = let origScope = i.scope try: - i.scope = q.scope.copy - i.scope.parent = origScope + i.scope = newScopeRef(origScope) body res = i.scope finally: i.scope = origScope -template withScope*(i: In, q: MinValue, body: untyped): untyped = +template withScope*(i: In, body: untyped): untyped = + let origScope = i.scope + try: + i.scope = newScopeRef(origScope) + body + finally: + i.scope = origScope + +template withDictScope*(i: In, s: ref MinScope, body: untyped): untyped = let origScope = i.scope try: - i.scope = q.scope.copy - i.scope.parent = origScope + var scope = s.copy + scope.parent = origscope + i.scope = scope body - q.scope = i.scope finally: i.scope = origScope

@@ -124,27 +131,31 @@ op.prc(i)

of minValOp: if op.val.kind == minQuotation: var q = op.val - i.withScope(q, newscope): - for e in q.qVal: + i.withScope(newscope): + for e in q.quot: i.push e else: i.push(op.val) proc dequote*(i: In, q: var MinValue) {.extern:"min_exported_symbol_$1".}= - if q.kind != minQuotation and q.kind != minDictionary: - i.push(q) - else: - i.withScope(q): - for v in q.qVal: + if q.kind == minDictionary: + i.withScope(q.scope): + for v in q.quot: i.push v + elif q.kind == minQuotation: + i.withScope(): + for v in q.quot: + i.push v + else: + i.push(q) proc apply*(i: In, q: var MinValue) {.gcsafe, extern:"min_exported_symbol_$1_2".}= var i2 = newMinInterpreter("<apply>") i2.trace = i.trace i2.scope = i.scope try: - i2.withScope(q): - for v in q.qVal: + i2.withScope(): + for v in q.quot: if (v.kind == minQuotation): var v2 = v i2.dequote(v2)

@@ -161,8 +172,8 @@ var i2 = newMinInterpreter("<call>")

i2.trace = i.trace i2.scope = i.scope try: - i2.withScope(q): - for v in q.qVal: + i2.withScope(): + for v in q.quot: i2.push v except: i.currSym = i2.currSym

@@ -190,9 +201,10 @@ discard i.trace.pop

else: if (val.kind == minDictionary): var v = val - i.dequote(v) - # Clear the initial quotation; only used when parsing a dictionary for the first time - v.qVal = @[] + if val.scope.symbols.len == 0: + i.dequote(v) + # Clear the initial quotation; only used when parsing a dictionary for the first time + v.quot = @[] i.stack.add(val) proc pop*(i: In): MinValue {.extern:"min_exported_symbol_$1".}=

@@ -216,7 +228,7 @@ i.stackcopy = i.stack

try: val = i.parser.parseMinValue(i) if parseOnly: - q.qVal.add val + q.quot.add val else: i.push val except MinRuntimeError:
M core/parser.nimcore/parser.nim

@@ -73,11 +73,13 @@ filename*: string

case kind*: MinKind of minInt: intVal*: BiggestInt of minFloat: floatVal*: BiggestFloat - of minQuotation, minDictionary: + of minDictionary: + q*: seq[MinValue] + scope*: ref MinScope + obj*: pointer + objType*: string + of minQuotation: qVal*: seq[MinValue] - scope*: ref MinScope - obj*: pointer # Used only for dicts - objType*: string # Used only for dicts of minString: strVal*: string of minSymbol: symVal*: string of minBool: boolVal*: bool

@@ -131,9 +133,28 @@

proc raiseEmptyStack*() {.extern:"min_exported_symbol_$1".}= raise MinEmptyStackError(msg: "Insufficient items on the stack") -proc dVal*(v: MinValue): CritBitTree[MinOperator] {.extern:"min_exported_symbol_$1".}= +proc dVal*(v: MinValue): CritBitTree[MinOperator] {.inline, extern:"min_exported_symbol_$1".}= + if v.kind != minDictionary: + raiseInvalid("dVal - Dictionary expected, got " & $v.kind) + if v.scope.isNil: + return CritBitTree[MinOperator]() + return v.scope.symbols + +proc quot*(v: MinValue): var seq[MinValue] {.inline, extern:"min_exported_symbol_$1".}= + if v.kind != minDictionary and v.kind != minQuotation: + raiseInvalid("quot - Dictionary or quotation expected, got " & $v.kind) + if v.kind == minDictionary: + return v.q + else: + return v.qVal + +proc `quot=`*(v: var MinValue, quot: seq[MinValue]) {.inline, extern:"min_exported_symbol_qValEq".}= + if v.kind != minDictionary and v.kind != minQuotation: + raiseInvalid("quot= - Dictionary or quotation expected, got " & $v.kind) if v.kind == minDictionary: - return v.scope.symbols + v.q = quot + else: + v.qVal = quot const errorMessages: array[MinParserError, string] = [

@@ -547,26 +568,26 @@ result = MinValue(kind: minFloat, floatVal: parseFloat(p.a))

discard getToken(p) of tkBracketLe: var q = newSeq[MinValue](0) - var oldscope = i.scope - var newscope = newScopeRef(i.scope) - i.scope = newscope + #var oldscope = i.scope + #var newscope = newScopeRef(i.scope) + #i.scope = newscope discard getToken(p) while p.token != tkBracketRi: q.add p.parseMinValue(i) eat(p, tkBracketRi) - i.scope = oldscope - result = MinValue(kind: minQuotation, qVal: q, scope: newscope) + #i.scope = oldscope + result = MinValue(kind: minQuotation, qVal: q)#, scope: newscope) of tkBraceLe: var q = newSeq[MinValue](0) - var oldscope = i.scope - var newscope = newScopeRef(i.scope) - i.scope = newscope + #var oldscope = i.scope + #var newscope = newScopeRef(i.scope) + #i.scope = newscope discard getToken(p) while p.token != tkBraceRi: q.add p.parseMinValue(i) eat(p, tkBraceRi) - i.scope = oldscope - result = MinValue(kind: minDictionary, qVal: q, scope: newscope) + #i.scope = oldscope + result = MinValue(kind: minDictionary, q: q, scope: newScopeRef(nil)) of tkSymbol: result = MinValue(kind: minSymbol, symVal: p.a, column: p.getColumn, line: p.lineNumber, filename: p.filename) p.a = ""

@@ -591,8 +612,6 @@ of minQuotation:

var q = "(" for i in a.qVal: q = q & $i & " " - if not a.objType.isNil: - q = q & ";" & a.objType q = q.strip & ")" return q of minDictionary:

@@ -627,8 +646,6 @@ of minQuotation:

var q = "(" for i in a.qVal: q = q & $i & " " - if not a.objType.isNil: - q = q & ";" & a.objType q = q.strip & ")" return q of minDictionary:
M core/utils.nimcore/utils.nim

@@ -39,6 +39,7 @@ proc finalize*(scope: ref MinScope, name: string = "") {.extern:"min_exported_symbol_$1".}=

var mdl = newDict(scope) mdl.scope = scope mdl.objType = "module" + mdl.quot = @[] let op = proc(i: In) {.closure.} = i.evaluating = true i.push mdl
M core/value.nimcore/value.nim

@@ -34,9 +34,9 @@ return MinValue(kind: minString, strVal: $s)

proc newVal*(q: seq[MinValue], parentScope: ref MinScope, dictionary = false): MinValue {.extern:"min_exported_symbol_$1_3".}= if dictionary: - return MinValue(kind: minDictionary, qVal: q, scope: newScopeRef(parentScope)) + return MinValue(kind: minDictionary, q: q)#, scope: newScopeRef(parentScope)) else: - return MinValue(kind: minQuotation, qVal: q, scope: newScopeRef(parentScope)) + return MinValue(kind: minQuotation, qVal: q)#, scope: newScopeRef(parentScope)) proc newVal*(i: BiggestInt): MinValue {.extern:"min_exported_symbol_$1_4".}= return MinValue(kind: minInt, intVal: i)

@@ -48,7 +48,7 @@ proc newVal*(s: bool): MinValue {.extern:"min_exported_symbol_$1_6".}=

return MinValue(kind: minBool, boolVal: s) proc newDict*(parentScope: ref MinScope): MinValue {.extern:"min_exported_symbol_$1".}= - return MinValue(kind: minDictionary, qVal: newSeq[MinValue](0), scope: newScopeRef(parentScope)) + return MinValue(kind: minDictionary, q: newSeq[MinValue](0), scope: newScopeRef(parentScope)) proc newSym*(s: string): MinValue {.extern:"min_exported_symbol_$1".}= return MinValue(kind: minSymbol, symVal: s)
M lib/min_lang.nimlib/min_lang.nim

@@ -197,7 +197,7 @@ def.symbol("with") do (i: In):

let vals = i.expect("dict", "quot") var qscope = vals[0] let qprog = vals[1] - i.withScope(qscope): + i.withDictScope(qscope.scope): for v in qprog.qVal: i.push v
M tests/http.mintests/http.min

@@ -3,47 +3,47 @@ 'test import

"http" describe - "http://httpbin.org" :url + "http://postman-echo.com" :url - ("$1/get" (url) => % get-content from-json /headers /User-Agent "min http-module/$1" (version) => % ==) assert + ("$1/get" (url) => % get-content from-json /headers /user-agent "min http-module/$1" (version) => % ==) assert ("$1/get?test=Hello!" (url) => % "tests/test1.json" :file file download file fread from-json /args /test "Hello!" ==) assert "tests/test1.json" rm ( {} ( - ("$1/get?test=request" (url) => % %url) + ("$1/get" (url) => % %url) ("GET" %method) ({"it-it" :Accept-Language} %headers) (request) - ) tap /body from-json /headers /Accept-Language "it-it" == + ) tap /body from-json /headers /accept-language "it-it" == ) assert ( {} ( ("$1/put" (url) => % %url) ("PUT" %method) - ({"put" :test} to-json %body) + ({} to-json %body) (request) - ) tap /body from-json /json {"put" :test} == + ) tap /body from-json /data {} == ) assert ( {} ( ("$1/post" (url) => % %url) ("POST" %method) - ((("test" "post")) to-json %body) + ({"post" :test} to-json %body) (request) - ) tap /headers /content-type "application/json" == + ) tap /headers /content-type "^application/json" match ) assert ( {} ( ("$1/patch" (url) => % %url) ("PATCH" %method) - ({"patch" :test} to-json %body) + ({} to-json %body) (request) - ) tap /body from-json /json {"patch" :test} == + ) tap /body from-json /data {} == ) assert (
M tests/net.mintests/net.min

@@ -9,37 +9,23 @@ {} socket :cli1

{} socket :cli2 - {} socket "httpbin.org" 80 connect @cli1 + {} socket "postman-echo.com" 80 connect @cli1 "min v$1" (version) => % :user-agent - "GET /user-agent HTTP/1.1\r\nHost: httpbin.org\r\nUser-Agent: $1\r\n\r\n" (user-agent) => % :req + "GET /get HTTP/1.1\r\nHost: postman-echo.com\r\nUser-Agent: $1\r\n\r\n" (user-agent) => % :req "" :response cli1 req send cli1 recv-line :line (response line) => "\n" join @response - (line "\}" match not) + (line "HTTP/1.1 200 OK" == not) ( cli1 recv-line @line - (response line) => "\n" join @response + (response line) => "\n" join puts @response ) while - ;HTTP/1.1 200 OK - ;Connection: keep-alive - ;Server: meinheld/0.6.1 - ;Date: Sun, 19 Nov 2017 13:37:15 GMT - ;Content-Type: application/json - ;Access-Control-Allow-Origin: * - ;Access-Control-Allow-Credentials: true - ;X-Powered-By: Flask - ;X-Processed-Time: 0.00111794471741 - ;Content-Length: 34 - ;Via: 1.1 vegur - ; - ;{"user-agent": "min v0.16.0"} - - (response "\n\n" split 1 get from-json /user-agent user-agent ==) assert + (response "200 OK" match) assert (srv1 srv2 ==) assert (cli1 cli2 !=) assert