Merge branch 'devel' of github.com:Araq/Nimrod into devel
This commit is contained in:
commit
694fc87b1d
6 changed files with 109 additions and 61 deletions
|
|
@ -138,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) =
|
||||||
if n.sons[0].kind == nkClosure:
|
if n.sons[0].kind == nkClosure:
|
||||||
# XXX this produces quite inefficient code!
|
# XXX this produces quite inefficient code!
|
||||||
initLocExpr(p, n.sons[0].sons[1], a)
|
initLocExpr(p, n.sons[0].sons[1], a)
|
||||||
lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)])
|
lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
# the environment is guaranteed to contain the 'state' field at offset 0:
|
# the environment is guaranteed to contain the 'state' field at offset 0:
|
||||||
|
|
|
||||||
|
|
@ -121,14 +121,14 @@ type
|
||||||
capturedVars: seq[PSym] # captured variables in this environment
|
capturedVars: seq[PSym] # captured variables in this environment
|
||||||
deps: seq[TDep] # dependencies
|
deps: seq[TDep] # dependencies
|
||||||
up: PEnv
|
up: PEnv
|
||||||
tup: PType
|
obj: PType
|
||||||
|
|
||||||
TInnerContext {.final.} = object
|
TInnerContext = object
|
||||||
fn: PSym
|
fn: PSym
|
||||||
closureParam: PSym
|
closureParam: PSym
|
||||||
localsToAccess: TIdNodeTable
|
localsToAccess: TIdNodeTable
|
||||||
|
|
||||||
TOuterContext {.final.} = object
|
TOuterContext = object
|
||||||
fn: PSym # may also be a module!
|
fn: PSym # may also be a module!
|
||||||
currentEnv: PEnv
|
currentEnv: PEnv
|
||||||
isIter: bool # first class iterator?
|
isIter: bool # first class iterator?
|
||||||
|
|
@ -139,8 +139,13 @@ type
|
||||||
up: POuterContext
|
up: POuterContext
|
||||||
|
|
||||||
closureParam, state, resultSym: PSym # only if isIter
|
closureParam, state, resultSym: PSym # only if isIter
|
||||||
tup: PType # only if isIter
|
obj: PType # only if isIter
|
||||||
|
|
||||||
|
proc createObj(owner: PSym, info: TLineInfo): PType =
|
||||||
|
result = newType(tyObject, owner)
|
||||||
|
rawAddSon(result, nil)
|
||||||
|
incl result.flags, tfFinal
|
||||||
|
result.n = newNodeI(nkRecList, info)
|
||||||
|
|
||||||
proc getStateType(iter: PSym): PType =
|
proc getStateType(iter: PSym): PType =
|
||||||
var n = newNodeI(nkRange, iter.info)
|
var n = newNodeI(nkRange, iter.info)
|
||||||
|
|
@ -185,13 +190,14 @@ proc getEnvParam(routine: PSym): PSym =
|
||||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||||
result = hidden.sym
|
result = hidden.sym
|
||||||
|
|
||||||
proc addField(tup: PType, s: PSym) =
|
proc addField(obj: PType; s: PSym) =
|
||||||
var field = newSym(skField, s.name, s.owner, s.info)
|
# because of 'gensym' support, we have to mangle the name with its ID.
|
||||||
|
# This is hacky but the clean solution is much more complex than it looks.
|
||||||
|
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
|
||||||
let t = skipIntLit(s.typ)
|
let t = skipIntLit(s.typ)
|
||||||
field.typ = t
|
field.typ = t
|
||||||
field.position = sonsLen(tup)
|
field.position = sonsLen(obj.n)
|
||||||
addSon(tup.n, newSymNode(field))
|
addSon(obj.n, newSymNode(field))
|
||||||
rawAddSon(tup, t)
|
|
||||||
|
|
||||||
proc initIterContext(c: POuterContext, iter: PSym) =
|
proc initIterContext(c: POuterContext, iter: PSym) =
|
||||||
c.fn = iter
|
c.fn = iter
|
||||||
|
|
@ -199,25 +205,24 @@ proc initIterContext(c: POuterContext, iter: PSym) =
|
||||||
|
|
||||||
var cp = getEnvParam(iter)
|
var cp = getEnvParam(iter)
|
||||||
if cp == nil:
|
if cp == nil:
|
||||||
c.tup = newType(tyTuple, iter)
|
c.obj = createObj(iter, iter.info)
|
||||||
c.tup.n = newNodeI(nkRecList, iter.info)
|
|
||||||
|
|
||||||
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
||||||
incl(cp.flags, sfFromGeneric)
|
incl(cp.flags, sfFromGeneric)
|
||||||
cp.typ = newType(tyRef, iter)
|
cp.typ = newType(tyRef, iter)
|
||||||
rawAddSon(cp.typ, c.tup)
|
rawAddSon(cp.typ, c.obj)
|
||||||
addHiddenParam(iter, cp)
|
addHiddenParam(iter, cp)
|
||||||
|
|
||||||
c.state = createStateField(iter)
|
c.state = createStateField(iter)
|
||||||
addField(c.tup, c.state)
|
addField(c.obj, c.state)
|
||||||
else:
|
else:
|
||||||
c.tup = cp.typ.sons[0]
|
c.obj = cp.typ.sons[0]
|
||||||
assert c.tup.kind == tyTuple
|
assert c.obj.kind == tyObject
|
||||||
if c.tup.len > 0:
|
if c.obj.n.len > 0:
|
||||||
c.state = c.tup.n[0].sym
|
c.state = c.obj.n[0].sym
|
||||||
else:
|
else:
|
||||||
c.state = createStateField(iter)
|
c.state = createStateField(iter)
|
||||||
addField(c.tup, c.state)
|
addField(c.obj, c.state)
|
||||||
|
|
||||||
c.closureParam = cp
|
c.closureParam = cp
|
||||||
if iter.typ.sons[0] != nil:
|
if iter.typ.sons[0] != nil:
|
||||||
|
|
@ -244,8 +249,7 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
|
||||||
new(result)
|
new(result)
|
||||||
result.deps = @[]
|
result.deps = @[]
|
||||||
result.capturedVars = @[]
|
result.capturedVars = @[]
|
||||||
result.tup = newType(tyTuple, outerProc)
|
result.obj = createObj(outerProc, outerProc.info)
|
||||||
result.tup.n = newNodeI(nkRecList, outerProc.info)
|
|
||||||
result.up = up
|
result.up = up
|
||||||
result.attachedNode = n
|
result.attachedNode = n
|
||||||
|
|
||||||
|
|
@ -254,28 +258,28 @@ proc addCapturedVar(e: PEnv, v: PSym) =
|
||||||
if x == v: return
|
if x == v: return
|
||||||
# XXX meh, just add the state field for every closure for now, it's too
|
# XXX meh, just add the state field for every closure for now, it's too
|
||||||
# hard to figure out if it comes from a closure iterator:
|
# hard to figure out if it comes from a closure iterator:
|
||||||
if e.tup.len == 0: addField(e.tup, createStateField(v.owner))
|
if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner))
|
||||||
e.capturedVars.add(v)
|
e.capturedVars.add(v)
|
||||||
addField(e.tup, v)
|
addField(e.obj, v)
|
||||||
|
|
||||||
proc addDep(e, d: PEnv, owner: PSym): PSym =
|
proc addDep(e, d: PEnv, owner: PSym): PSym =
|
||||||
for x, field in items(e.deps):
|
for x, field in items(e.deps):
|
||||||
if x == d: return field
|
if x == d: return field
|
||||||
var pos = sonsLen(e.tup)
|
var pos = sonsLen(e.obj.n)
|
||||||
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
|
result = newSym(skField, getIdent(upName & $pos), owner, owner.info)
|
||||||
result.typ = newType(tyRef, owner)
|
result.typ = newType(tyRef, owner)
|
||||||
result.position = pos
|
result.position = pos
|
||||||
assert d.tup != nil
|
assert d.obj != nil
|
||||||
rawAddSon(result.typ, d.tup)
|
rawAddSon(result.typ, d.obj)
|
||||||
addField(e.tup, result)
|
addField(e.obj, result)
|
||||||
e.deps.add((d, result))
|
e.deps.add((d, result))
|
||||||
|
|
||||||
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
|
proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode =
|
||||||
# returns a[].b as a node
|
# returns a[].b as a node
|
||||||
var deref = newNodeI(nkHiddenDeref, info)
|
var deref = newNodeI(nkHiddenDeref, info)
|
||||||
deref.typ = a.typ.sons[0]
|
deref.typ = a.typ.sons[0]
|
||||||
assert deref.typ.kind == tyTuple
|
assert deref.typ.kind == tyObject
|
||||||
let field = getSymFromList(deref.typ.n, b.name)
|
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
|
||||||
assert field != nil, b.name.s
|
assert field != nil, b.name.s
|
||||||
addSon(deref, a)
|
addSon(deref, a)
|
||||||
result = newNodeI(nkDotExpr, info)
|
result = newNodeI(nkDotExpr, info)
|
||||||
|
|
@ -302,11 +306,11 @@ proc addClosureParam(i: PInnerContext, e: PEnv) =
|
||||||
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
|
cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info)
|
||||||
incl(cp.flags, sfFromGeneric)
|
incl(cp.flags, sfFromGeneric)
|
||||||
cp.typ = newType(tyRef, i.fn)
|
cp.typ = newType(tyRef, i.fn)
|
||||||
rawAddSon(cp.typ, e.tup)
|
rawAddSon(cp.typ, e.obj)
|
||||||
addHiddenParam(i.fn, cp)
|
addHiddenParam(i.fn, cp)
|
||||||
else:
|
else:
|
||||||
e.tup = cp.typ.sons[0]
|
e.obj = cp.typ.sons[0]
|
||||||
assert e.tup.kind == tyTuple
|
assert e.obj.kind == tyObject
|
||||||
i.closureParam = cp
|
i.closureParam = cp
|
||||||
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
|
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
|
||||||
|
|
||||||
|
|
@ -357,7 +361,7 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym,
|
||||||
access = indirectAccess(access, addDep(e, it, i.fn), info)
|
access = indirectAccess(access, addDep(e, it, i.fn), info)
|
||||||
access = indirectAccess(access, local, info)
|
access = indirectAccess(access, local, info)
|
||||||
if o.isIter:
|
if o.isIter:
|
||||||
if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local)
|
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
|
||||||
else:
|
else:
|
||||||
incl(o.capturedVars, local.id)
|
incl(o.capturedVars, local.id)
|
||||||
idNodeTablePut(i.localsToAccess, local, access)
|
idNodeTablePut(i.localsToAccess, local, access)
|
||||||
|
|
@ -543,7 +547,7 @@ proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym =
|
||||||
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info)
|
||||||
incl(result.flags, sfShadowed)
|
incl(result.flags, sfShadowed)
|
||||||
result.typ = newType(tyRef, o.fn)
|
result.typ = newType(tyRef, o.fn)
|
||||||
result.typ.rawAddSon(e.tup)
|
result.typ.rawAddSon(e.obj)
|
||||||
|
|
||||||
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
|
||||||
if e.createdVar == nil:
|
if e.createdVar == nil:
|
||||||
|
|
@ -669,7 +673,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
|
||||||
var local = n.sym
|
var local = n.sym
|
||||||
|
|
||||||
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
|
if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id:
|
||||||
if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local)
|
if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local)
|
||||||
return indirectAccess(newSymNode(o.closureParam), local, n.info)
|
return indirectAccess(newSymNode(o.closureParam), local, n.info)
|
||||||
|
|
||||||
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,17 @@ type
|
||||||
# XXX 'break' should perform cleanup actions
|
# XXX 'break' should perform cleanup actions
|
||||||
# What does the C backend do for it?
|
# What does the C backend do for it?
|
||||||
|
|
||||||
proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
|
proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
|
||||||
if x != nil:
|
if x != nil:
|
||||||
stackTraceAux(c, x.next, x.comesFrom)
|
if recursionLimit == 0:
|
||||||
|
var calls = 0
|
||||||
|
var x = x
|
||||||
|
while x != nil:
|
||||||
|
inc calls
|
||||||
|
x = x.next
|
||||||
|
msgWriteln($calls & " calls omitted\n")
|
||||||
|
return
|
||||||
|
stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
|
||||||
var info = c.debug[pc]
|
var info = c.debug[pc]
|
||||||
# we now use the same format as in system/except.nim
|
# we now use the same format as in system/except.nim
|
||||||
var s = toFilename(info)
|
var s = toFilename(info)
|
||||||
|
|
@ -222,13 +230,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||||
|
|
||||||
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
||||||
|
|
||||||
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
|
proc cleanUpOnException(c: PCtx; tos: PStackFrame):
|
||||||
|
tuple[pc: int, f: PStackFrame] =
|
||||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||||
var f = tos
|
var f = tos
|
||||||
while true:
|
while true:
|
||||||
while f.safePoints.isNil or f.safePoints.len == 0:
|
while f.safePoints.isNil or f.safePoints.len == 0:
|
||||||
f = f.next
|
f = f.next
|
||||||
if f.isNil: return -1
|
if f.isNil: return (-1, nil)
|
||||||
var pc2 = f.safePoints[f.safePoints.high]
|
var pc2 = f.safePoints[f.safePoints.high]
|
||||||
|
|
||||||
var nextExceptOrFinally = -1
|
var nextExceptOrFinally = -1
|
||||||
|
|
@ -244,13 +253,13 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
|
||||||
c.currentExceptionB = c.currentExceptionA
|
c.currentExceptionB = c.currentExceptionA
|
||||||
c.currentExceptionA = nil
|
c.currentExceptionA = nil
|
||||||
# execute the corresponding handler:
|
# execute the corresponding handler:
|
||||||
return pc2
|
return (pc2, f)
|
||||||
inc pc2
|
inc pc2
|
||||||
if nextExceptOrFinally >= 0:
|
if nextExceptOrFinally >= 0:
|
||||||
pc2 = nextExceptOrFinally
|
pc2 = nextExceptOrFinally
|
||||||
if c.code[pc2].opcode == opcFinally:
|
if c.code[pc2].opcode == opcFinally:
|
||||||
# execute the corresponding handler, but don't quit walking the stack:
|
# execute the corresponding handler, but don't quit walking the stack:
|
||||||
return pc2
|
return (pc2, f)
|
||||||
# not the right one:
|
# not the right one:
|
||||||
discard f.safePoints.pop
|
discard f.safePoints.pop
|
||||||
|
|
||||||
|
|
@ -869,19 +878,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcFinallyEnd:
|
of opcFinallyEnd:
|
||||||
if c.currentExceptionA != nil:
|
if c.currentExceptionA != nil:
|
||||||
# we are in a cleanup run:
|
# we are in a cleanup run:
|
||||||
pc = cleanUpOnException(c, tos, regs)-1
|
let (newPc, newTos) = cleanUpOnException(c, tos)
|
||||||
if pc < 0:
|
if newPc-1 < 0:
|
||||||
bailOut(c, tos)
|
bailOut(c, tos)
|
||||||
return
|
return
|
||||||
|
pc = newPc-1
|
||||||
|
if tos != newTos:
|
||||||
|
tos = newTos
|
||||||
|
move(regs, tos.slots)
|
||||||
of opcRaise:
|
of opcRaise:
|
||||||
let raised = regs[ra].node
|
let raised = regs[ra].node
|
||||||
c.currentExceptionA = raised
|
c.currentExceptionA = raised
|
||||||
c.exceptionInstr = pc
|
c.exceptionInstr = pc
|
||||||
|
let (newPc, newTos) = cleanUpOnException(c, tos)
|
||||||
# -1 because of the following 'inc'
|
# -1 because of the following 'inc'
|
||||||
pc = cleanUpOnException(c, tos, regs) - 1
|
if pc-1 < 0:
|
||||||
if pc < 0:
|
|
||||||
bailOut(c, tos)
|
bailOut(c, tos)
|
||||||
return
|
return
|
||||||
|
pc = newPc -1
|
||||||
|
if tos != newTos:
|
||||||
|
tos = newTos
|
||||||
|
move(regs, tos.slots)
|
||||||
of opcNew:
|
of opcNew:
|
||||||
ensureKind(rkNode)
|
ensureKind(rkNode)
|
||||||
let typ = c.types[instr.regBx - wordExcess]
|
let typ = c.types[instr.regBx - wordExcess]
|
||||||
|
|
|
||||||
|
|
@ -1034,6 +1034,7 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||||
proc setSlot(c: PCtx; v: PSym) =
|
proc setSlot(c: PCtx; v: PSym) =
|
||||||
# XXX generate type initialization here?
|
# XXX generate type initialization here?
|
||||||
if v.position == 0:
|
if v.position == 0:
|
||||||
|
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
|
||||||
v.position = c.prc.maxSlots
|
v.position = c.prc.maxSlots
|
||||||
c.prc.slots[v.position] = (inUse: true,
|
c.prc.slots[v.position] = (inUse: true,
|
||||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ proc raiseInvalidReply(expected, got: char) =
|
||||||
[$expected, $got])
|
[$expected, $got])
|
||||||
|
|
||||||
proc raiseNoOK(status: string) =
|
proc raiseNoOK(status: string) =
|
||||||
if status != "OK":
|
if status != "QUEUED" and status != "OK":
|
||||||
raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
|
raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status)
|
||||||
|
|
||||||
proc parseStatus(r: TRedis): TRedisStatus =
|
proc parseStatus(r: TRedis): TRedisStatus =
|
||||||
|
|
@ -64,6 +64,10 @@ proc parseStatus(r: TRedis): TRedisStatus =
|
||||||
proc parseInteger(r: TRedis): TRedisInteger =
|
proc parseInteger(r: TRedis): TRedisInteger =
|
||||||
var line = ""
|
var line = ""
|
||||||
r.socket.readLine(line)
|
r.socket.readLine(line)
|
||||||
|
|
||||||
|
if line == "+QUEUED": # inside of multi
|
||||||
|
return -1
|
||||||
|
|
||||||
if line == "":
|
if line == "":
|
||||||
raise newException(ERedis, "Server closed connection prematurely")
|
raise newException(ERedis, "Server closed connection prematurely")
|
||||||
|
|
||||||
|
|
@ -81,10 +85,7 @@ proc recv(sock: TSocket, size: int): TaintedString =
|
||||||
if sock.recv(cstring(result), size) != size:
|
if sock.recv(cstring(result), size) != size:
|
||||||
raise newException(EInvalidReply, "recv failed")
|
raise newException(EInvalidReply, "recv failed")
|
||||||
|
|
||||||
proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
|
proc parseSingle(r: TRedis, line:string, allowMBNil = False): TRedisString =
|
||||||
var line = ""
|
|
||||||
r.socket.readLine(line.TaintedString)
|
|
||||||
|
|
||||||
# Error.
|
# Error.
|
||||||
if line[0] == '-':
|
if line[0] == '-':
|
||||||
raise newException(ERedis, strip(line))
|
raise newException(ERedis, strip(line))
|
||||||
|
|
@ -94,6 +95,9 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
|
||||||
if line == "*-1":
|
if line == "*-1":
|
||||||
return RedisNil
|
return RedisNil
|
||||||
|
|
||||||
|
if line == "+QUEUED" or line == "+OK" : # inside of a transaction (multi)
|
||||||
|
return nil
|
||||||
|
|
||||||
if line[0] != '$':
|
if line[0] != '$':
|
||||||
raiseInvalidReply('$', line[0])
|
raiseInvalidReply('$', line[0])
|
||||||
|
|
||||||
|
|
@ -104,18 +108,41 @@ proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
|
||||||
var s = r.socket.recv(numBytes+2)
|
var s = r.socket.recv(numBytes+2)
|
||||||
result = strip(s.string)
|
result = strip(s.string)
|
||||||
|
|
||||||
proc parseMultiBulk(r: TRedis): TRedisList =
|
proc parseMultiLines(r: TRedis, countLine:string): TRedisList =
|
||||||
var line = TaintedString""
|
if countLine.string[0] != '*':
|
||||||
r.socket.readLine(line)
|
raiseInvalidReply('*', countLine.string[0])
|
||||||
|
|
||||||
if line.string[0] != '*':
|
var numElems = parseInt(countLine.string.substr(1))
|
||||||
raiseInvalidReply('*', line.string[0])
|
|
||||||
|
|
||||||
var numElems = parseInt(line.string.substr(1))
|
|
||||||
if numElems == -1: return nil
|
if numElems == -1: return nil
|
||||||
result = @[]
|
result = @[]
|
||||||
for i in 1..numElems:
|
for i in 1..numElems:
|
||||||
result.add(r.parseBulk())
|
var line = ""
|
||||||
|
r.socket.readLine(line.TaintedString)
|
||||||
|
if line[0] == '*': # after exec() may contain more multi-bulk replies
|
||||||
|
var parsed = r.parseMultiLines(line)
|
||||||
|
for item in parsed:
|
||||||
|
result.add(item)
|
||||||
|
else:
|
||||||
|
result.add(r.parseSingle(line))
|
||||||
|
|
||||||
|
proc parseBulk(r: TRedis, allowMBNil = False): TRedisString =
|
||||||
|
var line = ""
|
||||||
|
r.socket.readLine(line.TaintedString)
|
||||||
|
|
||||||
|
if line == "+QUEUED" or line == "+OK": # inside of a transaction (multi)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
return r.parseSingle(line, allowMBNil)
|
||||||
|
|
||||||
|
proc parseMultiBulk(r: TRedis): TRedisList =
|
||||||
|
var line = TaintedString""
|
||||||
|
r.socket.readLine(line)
|
||||||
|
|
||||||
|
if line == "+QUEUED": # inside of a transaction (multi)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
return r.parseMultiLines(line)
|
||||||
|
|
||||||
|
|
||||||
proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) =
|
proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) =
|
||||||
var request = "*" & $(1 + args.len()) & "\c\L"
|
var request = "*" & $(1 + args.len()) & "\c\L"
|
||||||
|
|
@ -722,6 +749,7 @@ proc discardMulti*(r: TRedis) =
|
||||||
proc exec*(r: TRedis): TRedisList =
|
proc exec*(r: TRedis): TRedisList =
|
||||||
## Execute all commands issued after MULTI
|
## Execute all commands issued after MULTI
|
||||||
r.sendCommand("EXEC")
|
r.sendCommand("EXEC")
|
||||||
|
|
||||||
return r.parseMultiBulk()
|
return r.parseMultiBulk()
|
||||||
|
|
||||||
proc multi*(r: TRedis) =
|
proc multi*(r: TRedis) =
|
||||||
|
|
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -1,8 +1,6 @@
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- fix GC issues
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue