Merge branch 'devel' into fix_15097

This commit is contained in:
metagn
2024-11-04 18:32:50 +03:00
committed by GitHub
18 changed files with 595 additions and 445 deletions

View File

@@ -1,44 +1,56 @@
import ropes, int128
type
Snippet = string
Builder = string
Snippet* = string
Builder* = object
buf*: string
template newBuilder(s: string): Builder =
s
template newBuilder*(s: string): Builder =
Builder(buf: s)
proc addIntValue(builder: var Builder, val: int) =
builder.addInt(val)
proc extract*(builder: Builder): Snippet =
builder.buf
proc addIntValue(builder: var Builder, val: int64) =
builder.addInt(val)
proc add*(builder: var Builder, s: string) =
builder.buf.add(s)
proc addIntValue(builder: var Builder, val: uint64) =
builder.addInt(val)
proc add*(builder: var Builder, s: char) =
builder.buf.add(s)
proc addIntValue(builder: var Builder, val: Int128) =
builder.addInt128(val)
proc addIntValue*(builder: var Builder, val: int) =
builder.buf.addInt(val)
template cIntValue(val: int): Snippet = $val
template cIntValue(val: int64): Snippet = $val
template cIntValue(val: uint64): Snippet = $val
template cIntValue(val: Int128): Snippet = $val
proc addIntValue*(builder: var Builder, val: int64) =
builder.buf.addInt(val)
proc addIntValue*(builder: var Builder, val: uint64) =
builder.buf.addInt(val)
proc addIntValue*(builder: var Builder, val: Int128) =
builder.buf.addInt128(val)
template cIntValue*(val: int): Snippet = $val
template cIntValue*(val: int64): Snippet = $val
template cIntValue*(val: uint64): Snippet = $val
template cIntValue*(val: Int128): Snippet = $val
import std/formatfloat
proc addFloatValue(builder: var Builder, val: float) =
builder.addFloat(val)
proc addFloatValue*(builder: var Builder, val: float) =
builder.buf.addFloat(val)
template cFloatValue(val: float): Snippet = $val
template cFloatValue*(val: float): Snippet = $val
proc int64Literal(i: BiggestInt; result: var Builder) =
proc addInt64Literal*(result: var Builder; i: BiggestInt) =
if i > low(int64):
result.add "IL64($1)" % [rope(i)]
else:
result.add "(IL64(-9223372036854775807) - IL64(1))"
proc uint64Literal(i: uint64; result: var Builder) =
proc addUint64Literal*(result: var Builder; i: uint64) =
result.add rope($i & "ULL")
proc intLiteral(i: BiggestInt; result: var Builder) =
proc addIntLiteral*(result: var Builder; i: BiggestInt) =
if i > low(int32) and i <= high(int32):
result.addIntValue(i)
elif i == low(int32):
@@ -49,19 +61,19 @@ proc intLiteral(i: BiggestInt; result: var Builder) =
else:
result.add "(IL64(-9223372036854775807) - IL64(1))"
proc intLiteral(i: Int128; result: var Builder) =
intLiteral(toInt64(i), result)
proc addIntLiteral*(result: var Builder; i: Int128) =
addIntLiteral(result, toInt64(i))
proc cInt64Literal(i: BiggestInt): Snippet =
proc cInt64Literal*(i: BiggestInt): Snippet =
if i > low(int64):
result = "IL64($1)" % [rope(i)]
else:
result = "(IL64(-9223372036854775807) - IL64(1))"
proc cUint64Literal(i: uint64): Snippet =
proc cUint64Literal*(i: uint64): Snippet =
result = $i & "ULL"
proc cIntLiteral(i: BiggestInt): Snippet =
proc cIntLiteral*(i: BiggestInt): Snippet =
if i > low(int32) and i <= high(int32):
result = rope(i)
elif i == low(int32):
@@ -72,5 +84,5 @@ proc cIntLiteral(i: BiggestInt): Snippet =
else:
result = "(IL64(-9223372036854775807) - IL64(1))"
proc cIntLiteral(i: Int128): Snippet =
proc cIntLiteral*(i: Int128): Snippet =
result = cIntLiteral(toInt64(i))

View File

@@ -42,6 +42,18 @@ template addVarWithType(builder: var Builder, kind: VarKind = Local, name: strin
builder.add(name)
builder.add(";\n")
template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
typ: Snippet, initializerBody: typed) =
## adds a variable declaration to the builder, with
## `initializerBody` building the initializer. initializer must be provided
builder.addVarHeader(kind)
builder.add(typ)
builder.add(" ")
builder.add(name)
builder.add(" = ")
initializerBody
builder.add(";\n")
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
typeBody, initializerBody: typed) =
## adds a variable declaration to the builder, with `typeBody` building the type, and
@@ -252,12 +264,12 @@ proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Sni
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.len
result.preFieldsLen = obj.buf.len
if result.baseKind == bcSupField:
obj.addField(name = "Sup", typ = baseType)
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.len:
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")
if info.named:
@@ -308,7 +320,7 @@ proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType:
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
result.preFieldsLen = obj.len
result.preFieldsLen = obj.buf.len
case result.baseKind
of bcNone:
# rest of the options add a field or don't need it due to inheritance,
@@ -328,7 +340,7 @@ proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType:
obj.addField(name = "Sup", typ = baseType)
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
if info.baseKind == bcNone and info.preFieldsLen == obj.len and
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
t.itemId notin m.g.graph.memberProcsPerType:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")

View File

@@ -93,6 +93,32 @@ template addElseBranch(builder: var Builder, stmt: var IfStmt, body: typed) =
body
builder.add("}")
proc addForRangeHeader(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
builder.add("for (")
builder.add(i)
builder.add(" = ")
builder.add(start)
builder.add("; ")
builder.add(i)
if inclusive:
builder.add(" <= ")
else:
builder.add(" < ")
builder.add(bound)
builder.add("; ")
builder.add(i)
builder.add("++) {\n")
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
addForRangeHeader(builder, i, start, bound, false)
body
builder.add("}\n")
template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
addForRangeHeader(builder, i, start, bound, true)
body
builder.add("}\n")
template addScope(builder: var Builder, body: typed) =
builder.add("{")
body

View File

@@ -209,8 +209,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
var lit = newRopeAppender()
intLiteral(first, lit)
let lit = cIntLiteral(first)
result = ("($4*)($1)+(($2)-($3))" %
[rdLoc(a), rdLoc(b), lit, dest],
lengthExpr)

View File

@@ -34,15 +34,15 @@ proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Builder) =
else: k = tyNil # don't go into the case variant that uses 'ty'
case k
of tyChar, tyNil:
intLiteral(n.intVal, result)
result.addIntLiteral(n.intVal)
of tyBool:
if n.intVal != 0: result.add "NIM_TRUE"
else: result.add "NIM_FALSE"
of tyInt64: int64Literal(n.intVal, result)
of tyUInt64: uint64Literal(uint64(n.intVal), result)
of tyInt64: result.addInt64Literal(n.intVal)
of tyUInt64: result.addUint64Literal(uint64(n.intVal))
else:
result.addCast(getTypeDesc(p.module, ty)):
intLiteral(n.intVal, result)
result.addIntLiteral(n.intVal)
of nkNilLit:
let k = if ty == nil: tyPointer else: skipTypes(ty, abstractVarRange).kind
if k == tyProc and skipTypes(ty, abstractVarRange).callConv == ccClosure:
@@ -51,17 +51,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Builder) =
if id == p.module.labels:
# not found in cache:
inc(p.module.labels)
var data = newBuilder("")
data.addVarWithTypeAndInitializer(kind = Const, name = tmpName):
data.add(getTypeDesc(p.module, ty))
do:
let t = getTypeDesc(p.module, ty)
p.module.s[cfsStrData].addVarWithInitializer(kind = Const, name = tmpName, typ = t):
var closureInit: StructInitializer
data.addStructInitializer(closureInit, kind = siOrderedStruct):
data.addField(closureInit, name = "ClP_0"):
data.add("NIM_NIL")
data.addField(closureInit, name = "ClE_0"):
data.add("NIM_NIL")
p.module.s[cfsStrData].add(data)
p.module.s[cfsStrData].addStructInitializer(closureInit, kind = siOrderedStruct):
p.module.s[cfsStrData].addField(closureInit, name = "ClP_0"):
p.module.s[cfsStrData].add("NIM_NIL")
p.module.s[cfsStrData].addField(closureInit, name = "ClE_0"):
p.module.s[cfsStrData].add("NIM_NIL")
result.add tmpName
elif k in {tyPointer, tyNil, tyProc}:
result.add rope("NIM_NIL")
@@ -107,7 +104,7 @@ proc genRawSetData(cs: TBitSet, size: int; result: var Builder) =
result.add "0123456789abcdef"[cs[i] div 16]
result.add "0123456789abcdef"[cs[i] mod 16]
else:
intLiteral(cast[BiggestInt](bitSetToWord(cs, size)), result)
result.addIntLiteral(cast[BiggestInt](bitSetToWord(cs, size)))
proc genSetNode(p: BProc, n: PNode; result: var Builder) =
var size = int(getSize(p.config, n.typ))
@@ -118,12 +115,9 @@ proc genSetNode(p: BProc, n: PNode; result: var Builder) =
if id == p.module.labels:
# not found in cache:
inc(p.module.labels)
var data = newBuilder("")
data.addVarWithTypeAndInitializer(kind = Const, name = tmpName):
data.add(getTypeDesc(p.module, n.typ))
do:
genRawSetData(cs, size, data)
p.module.s[cfsStrData].add(data)
let td = getTypeDesc(p.module, n.typ)
p.module.s[cfsStrData].addVarWithInitializer(kind = Const, name = tmpName, typ = td):
genRawSetData(cs, size, p.module.s[cfsStrData])
result.add tmpName
else:
genRawSetData(cs, size, result)
@@ -1065,8 +1059,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
# passing around `TLineInfo` + the set of files in the project.
msg.add toFileLineCol(p.config, e.info) & " "
msg.add genFieldDefect(p.config, field.name.s, disc.sym)
var strLit = newRopeAppender()
genStringLiteral(p.module, newStrNode(nkStrLit, msg), strLit)
var strLitBuilder = newBuilder("")
genStringLiteral(p.module, newStrNode(nkStrLit, msg), strLitBuilder)
let strLit = extract(strLitBuilder)
## discriminant check
let rt = rdLoc(test)
@@ -1456,7 +1451,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
var tmp: TLoc = getTemp(p, e.typ)
var L = 0
var appends = newBuilder("")
var appends: seq[Snippet] = @[]
var lens: seq[Snippet] = @[]
for i in 0..<e.len - 1:
# compute the length expression:
@@ -1465,23 +1460,21 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
let ra = rdLoc(a)
if skipTypes(e[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L)
appends.addCallStmt(cgsymValue(p.module, "appendChar"),
rstmp,
ra)
appends.add(cCall(cgsymValue(p.module, "appendChar"), rstmp, ra))
else:
if e[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, e[i + 1].strVal.len)
else:
lens.add(lenExpr(p, a))
appends.addCallStmt(cgsymValue(p.module, "appendString"),
rstmp,
ra)
appends.add(cCall(cgsymValue(p.module, "appendString"), rstmp, ra))
var exprL = cIntValue(L)
for len in lens:
exprL = cOp(Add, "NI", exprL, len)
p.s(cpsStmts).addAssignmentWithValue(tmp.snippet):
p.s(cpsStmts).addCall(cgsymValue(p.module, "rawNewString"), exprL)
p.s(cpsStmts).add appends
for append in appends:
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(append)
if d.k == locNone:
d = tmp
else:
@@ -1502,7 +1495,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# }
var
a, call: TLoc
appends = newBuilder("")
appends: seq[Snippet] = @[]
assert(d.k == locNone)
var L = 0
var lens: seq[Snippet] = @[]
@@ -1514,17 +1507,13 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
let ra = rdLoc(a)
if skipTypes(e[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L)
appends.addCallStmt(cgsymValue(p.module, "appendChar"),
rsd,
ra)
appends.add(cCall(cgsymValue(p.module, "appendChar"), rsd, ra))
else:
if e[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, e[i + 2].strVal.len)
else:
lens.add(lenExpr(p, a))
appends.addCallStmt(cgsymValue(p.module, "appendString"),
rsd,
ra)
appends.add(cCall(cgsymValue(p.module, "appendString"), rsd, ra))
var exprL = cIntValue(L)
for len in lens:
exprL = cOp(Add, "NI", exprL, len)
@@ -1535,15 +1524,15 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
exprL)
else:
call = initLoc(locCall, e, OnHeap)
var callRes = newBuilder("")
let rd = rdLoc(dest)
callRes.addCall(cgsymValue(p.module, "resizeString"),
call.snippet = cCall(cgsymValue(p.module, "resizeString"),
rd,
exprL)
call.snippet = callRes
genAssignment(p, dest, call, {})
gcUsage(p.config, e)
p.s(cpsStmts).add appends
for append in appends:
p.s(cpsStmts).addStmt():
p.s(cpsStmts).add(append)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
@@ -1553,13 +1542,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
var b = initLocExpr(p, e[2])
let seqType = skipTypes(e[1].typ, {tyVar})
var call = initLoc(locCall, e, OnHeap)
var callRes = newBuilder("")
let ra = rdLoc(a)
callRes.addCast(getTypeDesc(p.module, e[1].typ)):
callRes.addCall(cgsymValue(p.module, "incrSeqV3"),
call.snippet = cCast(getTypeDesc(p.module, e[1].typ),
cCall(cgsymValue(p.module, "incrSeqV3"),
if not p.module.compileToCpp: cCast(ptrType("TGenericSeq"), ra) else: ra,
genTypeInfoV1(p.module, seqType, e.info))
call.snippet = callRes
genTypeInfoV1(p.module, seqType, e.info)))
# emit the write barrier if required, but we can always move here, so
# use 'genRefAssign' for the seq.
genRefAssign(p, a, call)
@@ -1589,12 +1576,10 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
if optTinyRtti in p.config.globalOptions:
let fnName = cgsymValue(p.module, if needsInit: "nimNewObj" else: "nimNewObjUninit")
var bres = newBuilder("")
bres.addCast(getTypeDesc(p.module, typ)):
bres.addCall(fnName,
b.snippet = cCast(getTypeDesc(p.module, typ),
cCall(fnName,
sizeExpr,
cAlignof(getTypeDesc(p.module, bt)))
b.snippet = bres
cAlignof(getTypeDesc(p.module, bt))))
genAssignment(p, a, b, {})
else:
let ti = genTypeInfoV1(p.module, typ, a.lode.info)
@@ -1625,12 +1610,10 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
if p.config.selectedGC == gcGo:
# newObjRC1() would clash with unsureAsgnRef() - which is used by gcGo to
# implement the write barrier
var bres = newBuilder("")
bres.addCast(getTypeDesc(p.module, typ)):
bres.addCall(cgsymValue(p.module, "newObj"),
b.snippet = cCast(getTypeDesc(p.module, typ),
cCall(cgsymValue(p.module, "newObj"),
ti,
sizeExpr)
b.snippet = bres
sizeExpr))
let raa = addrLoc(p.config, a)
let rb = b.rdLoc
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
@@ -1638,22 +1621,18 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
rb)
else:
# use newObjRC1 as an optimization
var bres = newBuilder("")
bres.addCast(getTypeDesc(p.module, typ)):
bres.addCall(cgsymValue(p.module, "newObjRC1"),
b.snippet = cCast(getTypeDesc(p.module, typ),
cCall(cgsymValue(p.module, "newObjRC1"),
ti,
sizeExpr)
b.snippet = bres
sizeExpr))
let ra = a.rdLoc
let rb = b.rdLoc
p.s(cpsStmts).addAssignment(ra, rb)
else:
var bres = newBuilder("")
bres.addCast(getTypeDesc(p.module, typ)):
bres.addCall(cgsymValue(p.module, "newObj"),
b.snippet = cCast(getTypeDesc(p.module, typ),
cCall(cgsymValue(p.module, "newObj"),
ti,
sizeExpr)
b.snippet = bres
sizeExpr))
genAssignment(p, a, b, {})
# set the object type:
genObjectInit(p, cpsStmts, bt, a, constructRefObj)
@@ -1686,20 +1665,16 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
let typinfo = genTypeInfoV1(p.module, seqtype, dest.lode.info)
if p.config.selectedGC == gcGo:
# we need the write barrier
var callRes = newBuilder("")
callRes.addCast(st):
callRes.addCall(cgsymValue(p.module, "newSeq"), typinfo, length)
call.snippet = callRes
call.snippet = cCast(st,
cCall(cgsymValue(p.module, "newSeq"), typinfo, length))
let rad = addrLoc(p.config, dest)
let rc = call.rdLoc
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
cCast("void**", rad),
rc)
else:
var callRes = newBuilder("")
callRes.addCast(st):
callRes.addCall(cgsymValue(p.module, "newSeqRC1"), typinfo, length)
call.snippet = callRes
call.snippet = cCast(st,
cCall(cgsymValue(p.module, "newSeqRC1"), typinfo, length))
let rd = dest.rdLoc
let rc = call.rdLoc
p.s(cpsStmts).addAssignment(rd, rc)
@@ -1709,10 +1684,8 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
else:
let st = getTypeDesc(p.module, seqtype)
let typinfo = genTypeInfoV1(p.module, seqtype, dest.lode.info)
var callRes = newBuilder("")
callRes.addCast(st):
callRes.addCall(cgsymValue(p.module, "newSeq"), typinfo, length)
call.snippet = callRes
call.snippet = cCast(st,
cCall(cgsymValue(p.module, "newSeq"), typinfo, length))
genAssignment(p, dest, call, {})
proc genNewSeq(p: BProc, e: PNode) =
@@ -1755,11 +1728,10 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
else:
if d.k == locNone: d = getTemp(p, e.typ, needsInit=false) # bug #22560
let ra = a.rdLoc
var dres = newBuilder("")
dres.addCast(getTypeDesc(p.module, seqtype)):
dres.addCall(cgsymValue(p.module, "nimNewSeqOfCap"),
let dres = cCast(getTypeDesc(p.module, seqtype),
cCall(cgsymValue(p.module, "nimNewSeqOfCap"),
genTypeInfoV1(p.module, seqtype, e.info),
ra)
ra))
putIntoDest(p, d, e, dres)
gcUsage(p.config, e)
@@ -1771,15 +1743,14 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
if id == p.module.labels:
# expression not found in the cache:
inc(p.module.labels)
let td = getTypeDesc(p.module, t)
var data = newBuilder("")
data.addVarWithTypeAndInitializer(kind = Const, name = d.snippet):
data.add(getTypeDesc(p.module, t))
do:
data.addVarWithInitializer(kind = Const, name = d.snippet, typ = td):
# bug #23627; when generating const object fields, it's likely that
# we need to generate type infos for the object, which may be an object with
# custom hooks. We need to generate potential consts in the hooks first.
genBracedInit(p, n, isConst = true, t, data)
p.module.s[cfsData].add data
p.module.s[cfsData].add(extract(data))
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@@ -1942,8 +1913,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
if L < 10:
for i in 0..<L:
elem = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
var lit = newRopeAppender()
intLiteral(i, lit)
let lit = cIntLiteral(i)
elem.snippet = ropecg(p.module, "$1$3[$2]", [rdLoc(d), lit, dataField(p)])
elem.storage = OnHeap # we know that sequences are on the heap
arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage)
@@ -2518,12 +2488,12 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
# emit range check:
if n0t.kind in {tyUInt, tyUInt64}:
var first = newRopeAppender()
var first = newBuilder("")
genLiteral(p, n[1], dest, first)
var last = newRopeAppender()
var last = newBuilder("")
genLiteral(p, n[2], dest, last)
linefmt(p, cpsStmts, "if ($1 > ($5)($3)){ #raiseRangeErrorNoArgs(); ",
[rdCharLoc(a), first, last,
[rdCharLoc(a), extract(first), extract(last),
raiser, getTypeDesc(p.module, n0t)])
raiseInstr(p, p.s(cpsStmts))
linefmt p, cpsStmts, "}$n", []
@@ -2541,12 +2511,12 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
"(NI64)"
else:
""
var first = newRopeAppender()
var first = newBuilder("")
genLiteral(p, n[1], dest, first)
var last = newRopeAppender()
var last = newBuilder("")
genLiteral(p, n[2], dest, last)
linefmt(p, cpsStmts, "if ($5($1) < $2 || $5($1) > $3){ $4($1, $2, $3); ",
[rdCharLoc(a), first, last,
[rdCharLoc(a), extract(first), extract(last),
raiser, boundaryCast])
raiseInstr(p, p.s(cpsStmts))
linefmt p, cpsStmts, "}$n", []
@@ -2952,9 +2922,9 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
a, b: TLoc
var idx: TLoc
if nfAllConst in e.flags:
var elem = newRopeAppender()
var elem = newBuilder("")
genSetNode(p, e, elem)
putIntoDest(p, d, e, elem)
putIntoDest(p, d, e, extract(elem))
else:
if d.k == locNone: d = getTemp(p, e.typ)
if getSize(p.config, e.typ) > 8:
@@ -3043,12 +3013,11 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
if isConstClosure(n):
inc(p.module.labels)
var tmp = "CNSTCLOSURE" & rope(p.module.labels)
let td = getTypeDesc(p.module, n.typ)
var data = newBuilder("")
data.addVarWithTypeAndInitializer(kind = Const, name = tmp):
data.add(getTypeDesc(p.module, n.typ))
do:
data.addVarWithInitializer(kind = Const, name = tmp, typ = td):
genBracedInit(p, n, isConst = true, n.typ, data)
p.module.s[cfsData].add data
p.module.s[cfsData].add(extract(data))
putIntoDest(p, d, n, tmp, OnStatic)
else:
var tmp: TLoc
@@ -3075,8 +3044,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
if d.k == locNone: d = getTemp(p, n.typ)
for i in 0..<n.len:
arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
var lit = newRopeAppender()
intLiteral(i, lit)
let lit = cIntLiteral(i)
arr.snippet = subscript(rdLoc(d), lit)
expr(p, n[i], arr)
@@ -3215,11 +3183,12 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
if id == p.module.labels:
# expression not found in the cache:
inc(p.module.labels)
p.module.s[cfsData].addVarWithTypeAndInitializer(
kind = Const, name = tmp):
p.module.s[cfsData].add(getTypeDesc(p.module, t, dkConst))
do:
genBracedInit(p, n, isConst = true, t, p.module.s[cfsData])
let td = getTypeDesc(p.module, t, dkConst)
var data = newBuilder("")
data.addVarWithInitializer(
kind = Const, name = tmp, typ = td):
genBracedInit(p, n, isConst = true, t, data)
p.module.s[cfsData].add(extract(data))
if d.k == locNone:
fillLoc(d, locData, n, tmp, OnStatic)
@@ -3258,20 +3227,19 @@ proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) =
headerDecl.addDeclWithVisibility(Extern):
headerDecl.addVar(kind = Local, name = sym.loc.snippet,
typ = constType(getTypeDesc(m, sym.loc.t, dkVar)))
m.s[cfsData].add(headerDecl)
m.s[cfsData].add(extract(headerDecl))
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
p.module.g.generatedHeader.s[cfsData].add(extract(headerDecl))
proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
# add a suffix for hcr - will later init the global pointer with this data
let actualConstName = if q.hcrOn: sym.loc.snippet & "_const" else: sym.loc.snippet
var data = newRopeAppender()
let td = constType(getTypeDesc(q, sym.typ))
var data = newBuilder("")
data.addDeclWithVisibility(Private):
data.addVarWithTypeAndInitializer(Local, actualConstName):
data.add(constType(getTypeDesc(q, sym.typ)))
do:
data.addVarWithInitializer(Local, actualConstName, typ = td):
genBracedInit(q.initProc, sym.astdef, isConst = true, sym.typ, data)
q.s[cfsData].add data
q.s[cfsData].add(extract(data))
if q.hcrOn:
# generate the global pointer with the real name
q.s[cfsVars].addVar(kind = Global, name = sym.loc.snippet,
@@ -3348,9 +3316,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
putLocIntoDest(p, d, sym.loc)
of skConst:
if isSimpleConst(sym.typ):
var lit = newRopeAppender()
var lit = newBuilder("")
genLiteral(p, sym.astdef, sym.typ, lit)
putIntoDest(p, d, n, lit, OnStatic)
putIntoDest(p, d, n, extract(lit), OnStatic)
elif useAliveDataFromDce in p.module.flags:
genConstHeader(p.module, p.module, p, sym)
assert((sym.loc.snippet != "") and (sym.loc.t != nil))
@@ -3402,17 +3370,17 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
of nkNilLit:
if not isEmptyType(n.typ):
var lit = newRopeAppender()
var lit = newBuilder("")
genLiteral(p, n, lit)
putIntoDest(p, d, n, lit)
putIntoDest(p, d, n, extract(lit))
of nkStrLit..nkTripleStrLit:
var lit = newRopeAppender()
var lit = newBuilder("")
genLiteral(p, n, lit)
putDataIntoDest(p, d, n, lit)
putDataIntoDest(p, d, n, extract(lit))
of nkIntLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkCharLit:
var lit = newRopeAppender()
var lit = newBuilder("")
genLiteral(p, n, lit)
putIntoDest(p, d, n, lit)
putIntoDest(p, d, n, extract(lit))
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit:
genLineDir(p, n) # may be redundant, it is generated in fixupCall as well
@@ -3432,9 +3400,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
genCall(p, n, d)
of nkCurly:
if isDeepConstExpr(n) and n.len != 0:
var lit = newRopeAppender()
var lit = newBuilder("")
genSetNode(p, n, lit)
putIntoDest(p, d, n, lit)
putIntoDest(p, d, n, extract(lit))
else:
genSetConstr(p, n, d)
of nkBracket:
@@ -3781,6 +3749,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Builde
let base = t.skipTypes(abstractInst)[0]
let tmpName = getTempName(p.module)
# genBracedInit can modify cfsStrData, we need an intermediate builder:
var def = newBuilder("")
def.addVarWithTypeAndInitializer(
if isConst: Const else: Global,
@@ -3805,7 +3774,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Builde
for i in 0..<n.len:
def.addField(arrInit, name = ""):
genBracedInit(p, n[i], isConst, base, def)
p.module.s[cfsStrData].add def
p.module.s[cfsStrData].add extract(def)
result.add cCast(typ = getTypeDesc(p.module, t), value = cAddr(tmpName))
@@ -3813,6 +3782,7 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Buil
let base = t.skipTypes(abstractInst)[0]
let payload = getTempName(p.module)
# genBracedInit can modify cfsStrData, we need an intermediate builder:
var def = newBuilder("")
def.addVarWithTypeAndInitializer(
if isConst: AlwaysConst else: Global,
@@ -3832,7 +3802,7 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Buil
for i in 0..<n.len:
def.addField(arrInit, name = ""):
genBracedInit(p, n[i], isConst, base, def)
p.module.s[cfsStrData].add def
p.module.s[cfsStrData].add extract(def)
var resultInit: StructInitializer
result.addStructInitializer(resultInit, kind = siOrderedStruct):
@@ -3900,12 +3870,13 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, typ.elementType)
let arrLen = n.len
# genConstSimpleList can modify cfsStrData, we need an intermediate builder:
var data = newBuilder("")
data.addArrayVarWithInitializer(
kind = if isConst: AlwaysConst else: Global,
name = payload, elementType = ctype, len = arrLen):
genConstSimpleList(p, n, isConst, data)
p.module.s[cfsStrData].add(data)
p.module.s[cfsStrData].add(extract(data))
var openArrInit: StructInitializer
result.addStructInitializer(openArrInit, kind = siOrderedStruct):
result.addField(openArrInit, name = "Field0"):

View File

@@ -53,9 +53,9 @@ proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
res.add(cCast("NI", bitOr(cCast("NU", rope(s.len)), "NIM_STRLIT_FLAG")))
res.addField(strInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(res)
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
if s.isNil:
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
else:
@@ -85,9 +85,9 @@ proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bo
res.add(bitOr(rope(s.len), "NIM_STRLIT_FLAG"))
res.addField(structInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(res)
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var litName: string
if id == m.labels:
@@ -101,20 +101,19 @@ proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithTypeAndInitializer(
res.addVarWithInitializer(
if isConst: AlwaysConst else: Global,
name = tmp):
res.add("NimStringV2")
do:
name = tmp,
typ = "NimStringV2"):
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "len"):
res.addIntValue(n.strVal.len)
res.addField(strInit, name = "p"):
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
m.s[cfsStrData].add(res)
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
@@ -145,10 +144,10 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)

View File

@@ -146,16 +146,16 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
a.flags.incl(lfEnforceDeref)
expr(p, ri, a)
proc assignLabel(b: var TBlock; result: var Rope) {.inline.} =
proc assignLabel(b: var TBlock; result: var Builder) {.inline.} =
b.label = "LA" & b.id.rope
result.add b.label
proc blockBody(b: var TBlock; result: var Rope) =
result.add b.sections[cpsLocals]
proc blockBody(b: var TBlock; result: var Builder) =
result.add extract(b.sections[cpsLocals])
if b.frameLen > 0:
result.addf("FR_.len+=$1;$n", [b.frameLen.rope])
result.add(b.sections[cpsInit])
result.add(b.sections[cpsStmts])
result.add(extract(b.sections[cpsInit]))
result.add(extract(b.sections[cpsStmts]))
proc endBlock(p: BProc, blockEnd: Rope) =
let topBlock = p.blocks.len-1
@@ -281,7 +281,7 @@ proc genGotoVar(p: BProc; value: PNode) =
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Builder)
proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Builder) =
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
discard "nothing to do"
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
@@ -330,8 +330,9 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
value.kind in nkCallKinds and value[0].kind == nkSym and
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
var targetProc = p
var valueAsRope = ""
potentialValueInit(p, v, value, valueAsRope)
var valueBuilder = newBuilder("")
potentialValueInit(p, v, value, valueBuilder)
let valueAsRope = extract(valueBuilder)
if sfGlobal in v.flags:
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
value.kind == nkEmpty and
@@ -594,8 +595,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
return
let val = getOrdValue(it[j])
var lit = newRopeAppender()
intLiteral(toInt64(val)+id+1, lit)
let lit = cIntLiteral(toInt64(val)+id+1)
lineF(p, cpsStmts, "TMP$#_:$n", [lit])
genStmts(p, it.lastSon)
@@ -775,7 +775,7 @@ proc finallyActions(p: BProc) =
if finallyBlock != nil:
genSimpleBlock(p, finallyBlock[0])
proc raiseInstr(p: BProc; result: var Rope) =
proc raiseInstr(p: BProc; result: var Builder) =
if p.config.exc == excGoto:
let L = p.nestedTryStmts.len
if L == 0:
@@ -925,8 +925,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
[rdLoc(a), bitMask])
for j in 0..high(branches):
if branches[j] != "":
var lit = newRopeAppender()
intLiteral(j, lit)
let lit = cIntLiteral(j)
lineF(p, cpsStmts, "case $1: $n$2break;$n",
[lit, branches[j]])
lineF(p, cpsStmts, "}$n", []) # else statement:
@@ -964,22 +963,22 @@ proc genCaseRange(p: BProc, branch: PNode) =
for j in 0..<branch.len-1:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[p.config.cCompiler].props:
var litA = newRopeAppender()
var litB = newRopeAppender()
var litA = newBuilder("")
var litB = newBuilder("")
genLiteral(p, branch[j][0], litA)
genLiteral(p, branch[j][1], litB)
lineF(p, cpsStmts, "case $1 ... $2:$n", [litA, litB])
lineF(p, cpsStmts, "case $1 ... $2:$n", [extract(litA), extract(litB)])
else:
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
var litA = newRopeAppender()
var litA = newBuilder("")
genLiteral(p, v, litA)
lineF(p, cpsStmts, "case $1:$n", [litA])
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
inc(v.intVal)
else:
var litA = newRopeAppender()
var litA = newBuilder("")
genLiteral(p, branch[j], litA)
lineF(p, cpsStmts, "case $1:$n", [litA])
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement:
@@ -1641,8 +1640,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
[discriminatorTableDecl(p.module, t, field)])
var lit = newRopeAppender()
intLiteral(toInt64(lengthOrd(p.config, field.typ))+1, lit)
let lit = cIntLiteral(toInt64(lengthOrd(p.config, field.typ))+1)
lineCg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),

View File

@@ -47,11 +47,9 @@ proc generateThreadLocalStorage(m: BModule) =
if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
finishTypeDescriptions(m)
var typedef = newBuilder("")
typedef.addTypedef(name = "NimThreadVars"):
typedef.addSimpleStruct(m, name = "", baseType = ""):
typedef.add(m.g.nimtv)
m.s[cfsSeqTypes].add(typedef)
m.s[cfsSeqTypes].addTypedef(name = "NimThreadVars"):
m.s[cfsSeqTypes].addSimpleStruct(m, name = "", baseType = ""):
m.s[cfsSeqTypes].add(m.g.nimtv)
proc generateThreadVarsSize(m: BModule) =
if m.g.nimtv != "":

View File

@@ -76,12 +76,11 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
let arraySize = lengthOrd(c.p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
let oldLen = p.s(cpsStmts).len
let oldLen = p.s(cpsStmts).buf.len
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
if p.s(cpsStmts).len == oldLen:
if p.s(cpsStmts).buf.len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
@@ -119,14 +118,13 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
assert typ.kind == tySequence
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
var a = TLoc(snippet: accessor)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, lenExpr(c.p, a)])
let oldLen = p.s(cpsStmts).len
let oldLen = p.s(cpsStmts).buf.len
genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
if p.s(cpsStmts).len == oldLen:
if p.s(cpsStmts).buf.len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
@@ -160,7 +158,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
genTraverseProc(c, "(*a)".rope, typ.elementType)
let generatedProc = "$1 {$n$2$3$4}\n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
[header, extract(p.s(cpsLocals)), extract(p.s(cpsInit)), extract(p.s(cpsStmts))]
m.s[cfsProcHeaders].addf("$1;\n", [header])
m.s[cfsProcs].add(generatedProc)
@@ -189,7 +187,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
genTraverseProc(c, sLoc, s.loc.t)
let generatedProc = "$1 {$n$2$3$4}$n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
[header, extract(p.s(cpsLocals)), extract(p.s(cpsInit)), extract(p.s(cpsStmts))]
m.s[cfsProcHeaders].addf("$1;$n", [header])
m.s[cfsProcs].add(generatedProc)

View File

@@ -427,11 +427,9 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TypeDescKind
if cacheGetType(m.typeCache, sig) == "":
m.typeCache[sig] = result
#echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s
var struct = newBuilder("")
struct.addSimpleStruct(m, name = result, baseType = ""):
struct.addField(name = "len", typ = "NI")
struct.addField(name = "p", typ = ptrType(result & "_Content"))
m.s[cfsTypes].add(struct)
m.s[cfsTypes].addSimpleStruct(m, name = result, baseType = ""):
m.s[cfsTypes].addField(name = "len", typ = "NI")
m.s[cfsTypes].addField(name = "p", typ = ptrType(result & "_Content"))
pushType(m, t)
else:
result = getTypeForward(m, t, sig) & seqStar(m)
@@ -450,13 +448,12 @@ proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
if result == "":
discard getTypeDescAux(m, t, check, dkVar)
else:
var struct = newBuilder("")
struct.addSimpleStruct(m, name = result & "_Content", baseType = ""):
struct.addField(name = "cap", typ = "NI")
struct.addField(name = "data",
typ = getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkVar),
let dataTyp = getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkVar)
m.s[cfsTypes].addSimpleStruct(m, name = result & "_Content", baseType = ""):
m.s[cfsTypes].addField(name = "cap", typ = "NI")
m.s[cfsTypes].addField(name = "data",
typ = dataTyp,
isFlexArray = true)
m.s[cfsTypes].add(struct)
proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
@@ -685,7 +682,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
genRecordFieldsAux(m, n[0], rectype, check, result, unionPrefix)
# prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_'
var unionBody: Rope = ""
var unionBody = newBuilder("")
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
@@ -694,16 +691,16 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i
var a = newBuilder("")
genRecordFieldsAux(m, k, rectype, check, a, unionPrefix & $structName & ".")
if a.len != 0:
if a.buf.len != 0:
unionBody.addFieldWithStructType(m, rectype, structName):
unionBody.add(a)
unionBody.add(extract(a))
else:
genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix)
else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody.len != 0:
if unionBody.buf.len != 0:
result.addAnonUnion:
# XXX this has to be a named field for NIFC
result.add(unionBody)
result.add(extract(unionBody))
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
@@ -735,7 +732,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
result.addField(field, sname, typ, isFlexArray, initializer)
else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl:bool = false)
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Builder; asPtr: bool = false, isFwdDecl:bool = false)
proc addRecordFields(result: var Builder; m: BModule; typ: PType, check: var IntSet) =
genRecordFieldsAux(m, typ.n, typ, check, result)
@@ -743,14 +740,15 @@ proc addRecordFields(result: var Builder; m: BModule; typ: PType, check: var Int
let procs = m.g.graph.memberProcsPerType[typ.itemId]
var isDefaultCtorGen, isCtorGen: bool = false
for prc in procs:
var header: Rope = ""
if sfConstructor in prc.flags:
isCtorGen = true
if prc.typ.n.len == 1:
isDefaultCtorGen = true
if lfNoDecl in prc.loc.flags: continue
var header = newBuilder("")
genMemberProcHeader(m, prc, header, false, true)
result.addf "$1;$n", [header]
result.addStmt():
result.add(extract(header))
if isCtorGen and not isDefaultCtorGen:
var ch: IntSet = default(IntSet)
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
@@ -771,22 +769,24 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
if typ.baseClass != nil:
baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = newBuilder("")
result.addStruct(m, typ, name, baseType):
result.addRecordFields(m, typ, check)
var res = newBuilder("")
res.addStruct(m, typ, name, baseType):
res.addRecordFields(m, typ, check)
result = extract(res)
else:
var desc = newBuilder("")
desc.addRecordFields(m, typ, check)
result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType])
result = runtimeFormat(typ.sym.cgDeclFrmt, [name, extract(desc), baseType])
proc getTupleDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
result = newBuilder("")
result.addStruct(m, typ, name, ""):
var res = newBuilder("")
res.addStruct(m, typ, name, ""):
for i, a in typ.ikids:
result.addField(
res.addField(
name = "Field" & $i,
typ = getTypeDescAux(m, a, check, dkField))
result = extract(res)
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# A helper proc for handling cppimport patterns, involving numeric
@@ -827,12 +827,10 @@ proc getOpenArrayDesc(m: BModule; t: PType, check: var IntSet; kind: TypeDescKin
result = getTypeName(m, t, sig)
m.typeCache[sig] = result
let elemType = getTypeDescWeak(m, t.elementType, check, kind)
var typedef = newBuilder("")
typedef.addTypedef(name = result):
typedef.addSimpleStruct(m, name = "", baseType = ""):
typedef.addField(name = "Field0", typ = ptrType(elemType))
typedef.addField(name = "Field1", typ = "NI")
m.s[cfsTypes].add(typedef)
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].addSimpleStruct(m, name = "", baseType = ""):
m.s[cfsTypes].addField(name = "Field0", typ = ptrType(elemType))
m.s[cfsTypes].addField(name = "Field1", typ = "NI")
proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDescKind): Rope =
# returns only the type's name
@@ -904,28 +902,26 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
(sfImportc in t.sym.flags and t.sym.magic == mNone)):
m.typeCache[sig] = result
var size: int
var typedef = newBuilder("")
if firstOrd(m.config, t) < 0:
typedef.addTypedef(name = result):
typedef.add("NI32")
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].add("NI32")
size = 4
else:
size = int(getSize(m.config, t))
case size
of 1:
typedef.addTypedef(name = result):
typedef.add("NU8")
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].add("NU8")
of 2:
typedef.addTypedef(name = result):
typedef.add("NU16")
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].add("NU16")
of 4:
typedef.addTypedef(name = result):
typedef.add("NI32")
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].add("NI32")
of 8:
typedef.addTypedef(name = result):
typedef.add("NI64")
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].add("NI64")
else: internalError(m.config, t.sym.info, "getTypeDescAux: enum")
m.s[cfsTypes].add(typedef)
when false:
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
@@ -942,16 +938,15 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
var rettype: Snippet = ""
var desc = newBuilder("")
genProcParams(m, t, rettype, desc, check, true, true)
let params = extract(desc)
if not isImportedType(t):
var typedef = newBuilder("")
if t.callConv != ccClosure: # procedure vars may need a closure!
typedef.addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = desc)
m.s[cfsTypes].addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = params)
else:
typedef.addTypedef(name = result):
typedef.addSimpleStruct(m, name = "", baseType = ""):
typedef.addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = desc)
typedef.addField(name = "ClE_0", typ = "void*")
m.s[cfsTypes].add(typedef)
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].addSimpleStruct(m, name = "", baseType = ""):
m.s[cfsTypes].addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = params)
m.s[cfsTypes].addField(name = "ClE_0", typ = "void*")
of tySequence:
if optSeqDestructors in m.config.globalOptions:
result = getTypeDescWeak(m, t, check, kind)
@@ -968,14 +963,13 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
m.typeCache[sig] = result & seqStar(m)
if not isImportedType(t):
if skipTypes(t.elementType, typedescInst).kind != tyEmpty:
var struct = newBuilder("")
let et = getTypeDescAux(m, t.elementType, check, kind)
let baseType = cgsymValue(m, "TGenericSeq")
struct.addSimpleStruct(m, name = result, baseType = baseType):
struct.addField(
m.s[cfsSeqTypes].addSimpleStruct(m, name = result, baseType = baseType):
m.s[cfsSeqTypes].addField(
name = "data",
typ = getTypeDescAux(m, t.elementType, check, kind),
typ = et,
isFlexArray = true)
m.s[cfsSeqTypes].add struct
else:
result = rope("TGenericSeq")
result.add(seqStar(m))
@@ -983,11 +977,9 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t.elementType, check, kind)
var typedef = newBuilder("")
typedef.addArrayTypedef(name = result, len = 1):
typedef.add(foo)
m.s[cfsTypes].add(typedef)
let et = getTypeDescAux(m, t.elementType, check, kind)
m.s[cfsTypes].addArrayTypedef(name = result, len = 1):
m.s[cfsTypes].add(et)
of tyArray:
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
if n <= 0: n = 1 # make an array of at least one element
@@ -995,10 +987,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
m.typeCache[sig] = result
if not isImportedType(t):
let e = getTypeDescAux(m, t.elementType, check, kind)
var typedef = newBuilder("")
typedef.addArrayTypedef(name = result, len = n):
typedef.add(e)
m.s[cfsTypes].add(typedef)
m.s[cfsTypes].addArrayTypedef(name = result, len = n):
m.s[cfsTypes].add(e)
of tyObject, tyTuple:
let tt = origTyp.skipTypes({tyDistinct})
if isImportedCppType(t) and tt.kind == tyGenericInst:
@@ -1106,16 +1096,15 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope =
var rettype: Snippet = ""
var desc = newBuilder("")
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
let params = extract(desc)
if not isImportedType(t):
var typedef = newBuilder("")
if t.callConv != ccClosure or kind != clFull:
typedef.addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = desc)
m.s[cfsTypes].addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = params)
else:
typedef.addTypedef(name = result):
typedef.addSimpleStruct(m, name = "", baseType = ""):
typedef.addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = desc)
typedef.addField(name = "ClE_0", typ = "void*")
m.s[cfsTypes].add(typedef)
m.s[cfsTypes].addTypedef(name = result):
m.s[cfsTypes].addSimpleStruct(m, name = "", baseType = ""):
m.s[cfsTypes].addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = params)
m.s[cfsTypes].addField(name = "ClE_0", typ = "void*")
proc finishTypeDescriptions(m: BModule) =
var i = 0
@@ -1158,7 +1147,7 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
params = "(" & params & ")"
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl: bool = false) =
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Builder; asPtr: bool = false, isFwdDecl: bool = false) =
assert sfCppMember * prc.flags != {}
let isCtor = sfConstructor in prc.flags
var check = initIntSet()
@@ -1206,14 +1195,15 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
params, fnConst, override, superCall])
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; visibility: var DeclVisibility, asPtr: bool, addAttributes: bool) =
proc genProcHeader(m: BModule; prc: PSym; result: var Builder; visibility: var DeclVisibility, asPtr: bool, addAttributes: bool) =
# using static is needed for inline procs
var check = initIntSet()
fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var rettype: Snippet = ""
var params = newBuilder("")
genProcParams(m, prc.typ, rettype, params, check, true, false)
var desc = newBuilder("")
genProcParams(m, prc.typ, rettype, desc, check, true, false)
let params = extract(desc)
# handle the 2 options for hotcodereloading codegen - function pointer
# (instead of forward declaration) or header for function body with "_actual" postfix
var name = prc.loc.snippet
@@ -1513,14 +1503,21 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
m.s[cfsTypeInit1].addArrayVarWithInitializer(
kind = Global,
name = enumArray,
elementType = "char* NIM_CONST", # XXX maybe do this in `addVar`
elementType = constPtrType("char"),
len = typ.n.len):
m.s[cfsTypeInit1].add(enumNames)
m.s[cfsTypeInit3].addf("for ($1 = 0; $1 < $2; $1++) {$n" &
"$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
"$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
rope(typ.n.len), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
m.s[cfsTypeInit3].add(specialCases)
m.s[cfsTypeInit1].add(extract(enumNames))
m.s[cfsTypeInit3].addForRangeExclusive(i = counter,
start = cIntValue(0),
bound = cIntValue(typ.n.len)):
let nodeLoc = subscript(m.typeNodesName,
cOp(Add, "NI", counter, cIntValue(firstNimNode)))
m.s[cfsTypeInit3].addFieldAssignment(nodeLoc, "kind", cIntValue(1))
m.s[cfsTypeInit3].addFieldAssignment(nodeLoc, "offset", counter)
m.s[cfsTypeInit3].addFieldAssignment(nodeLoc, "name",
subscript(enumArray, counter))
m.s[cfsTypeInit3].addSubscriptAssignment(nodePtrs, counter,
cAddr(nodeLoc))
m.s[cfsTypeInit3].add(extract(specialCases))
let n = getNimNode(m)
m.s[cfsTypeInit3].addFieldAssignment(n, "len", typ.n.len)
m.s[cfsTypeInit3].addFieldAssignment(n, "kind", 0)
@@ -1528,8 +1525,9 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
cAddr(subscript(nodePtrs, cIntValue(0))))
m.s[cfsTypeInit3].addFieldAssignment(tiNameForHcr(m, name), "node", cAddr(n))
if hasHoles:
# 1 << 2 is {ntfEnumHole}
m.s[cfsTypeInit3].addf("$1.flags = 1<<2;$n", [tiNameForHcr(m, name)])
m.s[cfsTypeInit3].addFieldAssignment(tiNameForHcr(m, name), "flags",
# 1 << 2 is {ntfEnumHole}
cOp(Shl, "NU8", cIntValue(1), cIntValue(2)))
proc genSetInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
assert(typ.elementType != nil)
@@ -1555,10 +1553,11 @@ include ccgtrav
proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
genProc(m, s)
var params = newBuilder("")
var desc = newBuilder("")
var paramBuilder: ProcParamBuilder
params.addProcParams(paramBuilder):
params.addUnnamedParam(paramBuilder, typ = "void*")
desc.addProcParams(paramBuilder):
desc.addUnnamedParam(paramBuilder, typ = "void*")
let params = extract(desc)
let pt = procPtrTypeUnnamedNimCall(rettype = "void*", params = params)
m.s[cfsTypeInit3].addFieldAssignmentWithValue(result, "deepcopy"):
m.s[cfsTypeInit3].add(cCast(pt, s.loc.snippet))
@@ -1643,7 +1642,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: var Rope) =
proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: var Builder) =
let theProc = getAttachedOp(m.g.graph, t, op)
if theProc != nil and not isTrivialProc(m.g.graph, theProc):
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
@@ -1719,7 +1718,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
var flags = 0
if not canFormAcycle(m.g.graph, t): flags = flags or 1
var typeEntry = newRopeAppender()
var typeEntry = newBuilder("")
typeEntry.addFieldAssignmentWithValue(name, "destructor"):
typeEntry.addCast("void*"):
genHook(m, t, info, attachedDestructor, typeEntry)
@@ -1771,7 +1770,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
genProcPrototype(m, i)
typeEntry.addFieldAssignment(name, "vTable", vTablePointerName)
m.s[cfsTypeInit3].add typeEntry
m.s[cfsTypeInit3].add extract(typeEntry)
if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
@@ -1784,11 +1783,9 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
var flags = 0
if not canFormAcycle(m.g.graph, t): flags = flags or 1
var typeEntry = newRopeAppender()
var typeEntry = newBuilder("")
typeEntry.addDeclWithVisibility(Private):
typeEntry.addVarWithTypeAndInitializer(kind = Local, name = name):
typeEntry.add("TNimTypeV2")
do:
typeEntry.addVarWithInitializer(kind = Local, name = name, typ = "TNimTypeV2"):
var typeInit: StructInitializer
typeEntry.addStructInitializer(typeInit, kind = siNamedStruct):
typeEntry.addField(typeInit, name = "destructor"):
@@ -1843,7 +1840,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
else:
typeEntry.addField(typeInit, name = "flags"):
typeEntry.addIntValue(flags)
m.s[cfsVars].add typeEntry
m.s[cfsVars].add extract(typeEntry)
if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)

View File

@@ -16,7 +16,7 @@ import
rodutils, renderer, cgendata, aliases,
lowerings, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, pushpoppragmas,
mangleutils
mangleutils, cbuilderbase
from expanddefaults import caseObjDefaultBranch
@@ -138,6 +138,9 @@ proc cgFormatValue(result: var string; value: BiggestInt) =
proc cgFormatValue(result: var string; value: Int128) =
result.addInt128 value
template addf(result: var Builder, args: varargs[untyped]) =
result.buf.addf(args)
# TODO: please document
macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
args.expectKind nnkBracket
@@ -237,7 +240,15 @@ proc addIndent(p: BProc; result: var Rope) =
result[i] = '\t'
inc i
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
proc addIndent(p: BProc; result: var Builder) =
var i = result.buf.len
let newLen = i + p.blocks.len
result.buf.setLen newLen
while i < newLen:
result.buf[i] = '\t'
inc i
template appcg(m: BModule, c: var (Rope | Builder), frmt: FormatStr,
args: untyped) =
c.add(ropecg(m, frmt, args))
@@ -275,7 +286,7 @@ proc safeLineNm(info: TLineInfo): int =
proc genPostprocessDir(field1, field2, field3: string): string =
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options and line > 0:
if fileIdx == InvalidFileIdx:
@@ -283,7 +294,7 @@ proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
assert line >= 0
if optLineDir in p.config.options and line > 0:
if fileIdx == InvalidFileIdx:
@@ -291,7 +302,7 @@ proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLi
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
proc genCLineDir(r: var Builder, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
@@ -304,7 +315,7 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
else:
result = false
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
proc genCLineDir(r: var Builder, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
let lastFileIndex = p.lastLineInfo.fileIndex
if freshLineInfo(p, info):
@@ -328,7 +339,7 @@ proc genLineDir(p: BProc, t: PNode) =
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
proc genProc(m: BModule, prc: PSym)
proc raiseInstr(p: BProc; result: var Rope)
proc raiseInstr(p: BProc; result: var Builder)
template compileToCpp(m: BModule): untyped =
m.config.backend == backendCpp or sfCompileToCpp in m.module.flags
@@ -340,7 +351,6 @@ proc getTempName(m: BModule): Rope =
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
sfNoReturn in s.flags and m.config.exc != excGoto
include cbuilderbase
include cbuilderexprs
include cbuilderdecls
include cbuilderstmts
@@ -613,28 +623,29 @@ proc getIntTemp(p: BProc): TLoc =
linefmt(p, cpsLocals, "NI $1;$n", [result.snippet])
proc localVarDecl(p: BProc; n: PNode): Rope =
result = ""
var res = newBuilder("")
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
fillLoc(s.loc, locLocalVar, n, OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
res.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
genCLineDir(result, p, n.info, p.config)
genCLineDir(res, p, n.info, p.config)
result.add getTypeDesc(p.module, s.typ, dkVar)
res.add getTypeDesc(p.module, s.typ, dkVar)
if sfCodegenDecl notin s.flags:
if sfRegister in s.flags: result.add(" register")
if sfRegister in s.flags: res.add(" register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# decl.add(" GC_GUARD")
if sfVolatile in s.flags: result.add(" volatile")
if sfNoalias in s.flags: result.add(" NIM_NOALIAS")
result.add(" ")
result.add(s.loc.snippet)
if sfVolatile in s.flags: res.add(" volatile")
if sfNoalias in s.flags: res.add(" NIM_NOALIAS")
res.add(" ")
res.add(s.loc.snippet)
result = extract(res)
else:
result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.snippet])
result = runtimeFormat(s.cgDeclFrmt, [extract(res), s.loc.snippet])
proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned
@@ -770,7 +781,7 @@ proc genStmts(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genLiteral(p: BProc, n: PNode; result: var Builder)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc raiseExitCleanup(p: BProc, destroy: string)
@@ -807,7 +818,7 @@ $1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:
if p.module.s[cfsFrameDefines].buf.len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
cgsym(p.module, "nimFrame")
@@ -848,7 +859,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
rawMessage(m.config, hintDependency, lib.path.strVal)
var loadlib: Rope = ""
var loadlib = newBuilder("")
for i in 0..high(s):
inc(m.labels)
if i > 0: loadlib.add("||")
@@ -859,7 +870,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
loadlib.addf "))$n", []
appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError(",
[loadlib])
[extract(loadlib)])
genStringLiteral(m, lib.path, m.s[cfsDynLibInit])
m.s[cfsDynLibInit].addf ");$n", []
@@ -873,9 +884,9 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
m.s[cfsDynLibInit].add(p.s(cpsInit))
m.s[cfsDynLibInit].add(p.s(cpsStmts))
m.s[cfsVars].add(extract(p.s(cpsLocals)))
m.s[cfsDynLibInit].add(extract(p.s(cpsInit)))
m.s[cfsDynLibInit].add(extract(p.s(cpsStmts)))
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
@@ -995,12 +1006,12 @@ proc generateHeaders(m: BModule) =
#undef unix
""")
proc openNamespaceNim(namespace: string; result: var Rope) =
proc openNamespaceNim(namespace: string; result: var Builder) =
result.add("namespace ")
result.add(namespace)
result.add(" {\L")
proc closeNamespaceNim(result: var Rope) =
proc closeNamespaceNim(result: var Builder) =
result.add("}\L")
proc closureSetup(p: BProc, prc: PSym) =
@@ -1185,9 +1196,10 @@ proc getProcTypeCast(m: BModule, prc: PSym): Rope =
result = getTypeDesc(m, prc.loc.t)
if prc.typ.callConv == ccClosure:
var rettype: Snippet = ""
var params = newBuilder("")
var desc = newBuilder("")
var check = initIntSet()
genProcParams(m, prc.typ, rettype, params, check)
genProcParams(m, prc.typ, rettype, desc, check)
let params = extract(desc)
result = procPtrTypeUnnamed(rettype = rettype, params = params)
proc genProcBody(p: BProc; procBody: PNode) =
@@ -1201,14 +1213,14 @@ proc genProcBody(p: BProc; procBody: PNode) =
proc genProcAux*(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newRopeAppender()
var header = newBuilder("")
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
var visibility: DeclVisibility = None
if isCppMember:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header, visibility, asPtr = false, addAttributes = false)
var returnStmt: Rope = ""
var returnStmt: Snippet = ""
assert(prc.ast != nil)
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
@@ -1241,9 +1253,10 @@ proc genProcAux*(m: BModule, prc: PSym) =
discard "result init optimized out"
else:
initLocalVar(p, res, immediateAsgn=false)
returnStmt = "\t"
var returnBuilder = newBuilder("\t")
let rres = rdLoc(res.loc)
returnStmt.addReturn(rres)
returnBuilder.addReturn(rres)
returnStmt = extract(returnBuilder)
elif sfConstructor in prc.flags:
resNode.sym.loc.flags.incl lfIndirect
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
@@ -1278,27 +1291,27 @@ proc genProcAux*(m: BModule, prc: PSym) =
generatedProc.genCLineDir prc.info, m.config
generatedProc.addDeclWithVisibility(visibility):
if sfPure in prc.flags:
generatedProc.add(header)
generatedProc.add(extract(header))
generatedProc.finishProcHeaderWithBody():
generatedProc.add(p.s(cpsLocals))
generatedProc.add(p.s(cpsInit))
generatedProc.add(p.s(cpsStmts))
generatedProc.add(extract(p.s(cpsLocals)))
generatedProc.add(extract(p.s(cpsInit)))
generatedProc.add(extract(p.s(cpsStmts)))
else:
if m.hcrOn and isReloadable(m, prc):
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
# This fixes the use of methods and also the case when 2 functions within the same module
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
m.s[cfsProcHeaders].add(header)
m.s[cfsProcHeaders].add(extract(header))
m.s[cfsProcHeaders].finishProcHeaderAsProto()
generatedProc.add(header)
generatedProc.add(extract(header))
generatedProc.finishProcHeaderWithBody():
if optStackTrace in prc.options:
generatedProc.add(p.s(cpsLocals))
generatedProc.add(extract(p.s(cpsLocals)))
var procname = makeCString(prc.name.s)
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
else:
generatedProc.add(p.s(cpsLocals))
generatedProc.add(extract(p.s(cpsLocals)))
if optProfiler in prc.options:
# invoke at proc entry for recursion:
p.s(cpsInit).add('\t')
@@ -1307,15 +1320,15 @@ proc genProcAux*(m: BModule, prc: PSym) =
# this pair of {} is required for C++ (C++ is weird with its
# control flow integrity checks):
generatedProc.addScope():
generatedProc.add(p.s(cpsInit))
generatedProc.add(p.s(cpsStmts))
generatedProc.add(extract(p.s(cpsInit)))
generatedProc.add(extract(p.s(cpsStmts)))
generatedProc.addLabel("BeforeRet_")
else:
generatedProc.add(p.s(cpsInit))
generatedProc.add(p.s(cpsStmts))
generatedProc.add(extract(p.s(cpsInit)))
generatedProc.add(extract(p.s(cpsStmts)))
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
generatedProc.add(returnStmt)
m.s[cfsProcs].add(generatedProc)
m.s[cfsProcs].add(extract(generatedProc))
if isReloadable(m, prc):
m.s[cfsDynLibInit].add('\t')
m.s[cfsDynLibInit].addAssignmentWithValue(prc.loc.snippet):
@@ -1356,13 +1369,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
'"' & name & '"')
elif not containsOrIncl(m.declaredProtos, sym.id):
let asPtr = isReloadable(m, sym)
var header = newRopeAppender()
var header = newBuilder("")
var visibility: DeclVisibility = None
genProcHeader(m, sym, header, visibility, asPtr = asPtr, addAttributes = true)
if asPtr:
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
# genProcHeader would give variable declaration, add it directly
m.s[cfsProcHeaders].add(header)
m.s[cfsProcHeaders].add(extract(header))
else:
let extraVis =
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
@@ -1371,7 +1384,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
None
m.s[cfsProcHeaders].addDeclWithVisibility(extraVis):
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
m.s[cfsProcHeaders].add(header)
m.s[cfsProcHeaders].add(extract(header))
m.s[cfsProcHeaders].finishProcHeaderAsProto()
# TODO: figure out how to rename this - it DOES generate a forward declaration
@@ -1498,7 +1511,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.snippet,
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
proc addNimDefines(result: var Builder; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
platform.CPU[conf.target.targetCPU].intSize.rope])
if conf.cppCustomNamespace.len > 0:
@@ -1522,9 +1535,10 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
rope(getCompileCFileCmd(conf, cfile))]
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
result = getCopyright(conf, cfile)
if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L")
addNimDefines(result, conf)
var res = newBuilder(getCopyright(conf, cfile))
if conf.hcrOn: res.add("#define NIM_HOT_CODE_RELOADING\L")
addNimDefines(res, conf)
result = extract(res)
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
## Returns a mangled module name.
@@ -1567,8 +1581,9 @@ proc genMainProc(m: BModule) =
assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
n.info = prc.annex.path.info
var strLit = newRopeAppender()
genStringLiteral(m, n, strLit)
var strLitBuilder = newBuilder("")
genStringLiteral(m, n, strLitBuilder)
let strLit = extract(strLitBuilder)
appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" &
"\t\t#nimLoadLibraryError($2);$N",
[handle, strLit])
@@ -1780,10 +1795,10 @@ proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag])
proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] =
# called from IC.
result = {}
if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
if m.hcrOn or m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
result.incl HasModuleInitProc
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
if m.s[i].buf.len != 0:
result.incl HasDatInitProc
break
@@ -1836,7 +1851,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
m.s[cfsInitProc].add(hcrModuleMeta)
return
if m.s[cfsDatInitProc].len > 0:
if m.s[cfsDatInitProc].buf.len > 0:
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
g.mainDatInit.addf("\t$1();$N", [datInit])
@@ -1848,7 +1863,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
if m.s[cfsInitProc].buf.len > 0:
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
let initCall = "\t$1();$N" % [init]
if sfMainModule in m.module.flags:
@@ -1865,22 +1880,22 @@ proc genDatInitCode(m: BModule) =
var moduleDatInitRequired = m.hcrOn
var prc = "$1 N_NIMCALL(void, $2)(void) {$N" %
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)]
var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" %
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)])
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
if m.s[i].buf.len != 0:
moduleDatInitRequired = true
prc.add(m.s[i])
prc.add(extract(m.s[i]))
prc.addf("}$N$N", [])
if moduleDatInitRequired:
m.s[cfsDatInitProc].add(prc)
m.s[cfsDatInitProc].add(extract(prc))
#rememberFlag(m.g.graph, m.module, HasDatInitProc)
# Very similar to the contents of symInDynamicLib - basically only the
@@ -1907,8 +1922,8 @@ proc genInitCode(m: BModule) =
## into other modules, only simple rope manipulations are allowed
var moduleInitRequired = m.hcrOn
let initname = getInitName(m)
var prc = "$1 N_NIMCALL(void, $2)(void) {$N" %
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" %
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname])
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
@@ -1931,13 +1946,13 @@ proc genInitCode(m: BModule) =
[getModuleDllPath(m, m.module)])
template writeSection(thing: untyped, section: TCProcSection, addHcrGuards = false) =
if m.thing.s(section).len > 0:
if m.thing.s(section).buf.len > 0:
moduleInitRequired = true
if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n")
prc.add(m.thing.s(section))
prc.add(extract(m.thing.s(section)))
if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n")
if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
if m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
# Give this small function its own scope
prc.addf("{$N", [])
# Keep a bogus frame in case the code needs one
@@ -1957,7 +1972,7 @@ proc genInitCode(m: BModule) =
prc.addf("{$N", [])
writeSection(initProc, cpsLocals)
if m.initProc.s(cpsInit).len > 0 or m.initProc.s(cpsStmts).len > 0:
if m.initProc.s(cpsInit).buf.len > 0 or m.initProc.s(cpsStmts).buf.len > 0:
moduleInitRequired = true
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
# BUT: the generated init code might depend on a current frame, so
@@ -2011,14 +2026,14 @@ proc genInitCode(m: BModule) =
prc.add(ex)
if moduleInitRequired or sfMainModule in m.module.flags:
m.s[cfsInitProc].add(prc)
m.s[cfsInitProc].add(extract(prc))
#rememberFlag(m.g.graph, m.module, HasModuleInitProc)
genDatInitCode(m)
if m.hcrOn:
m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", [])
m.s[cfsInitProc].add(m.hcrCreateTypeInfosProc)
m.s[cfsInitProc].add(extract(m.hcrCreateTypeInfosProc))
m.s[cfsInitProc].addf("}$N$N", [])
registerModuleToMain(m.g, m)
@@ -2060,31 +2075,32 @@ proc postprocessCode(conf: ConfigRef, r: var Rope) =
proc genModule(m: BModule, cfile: Cfile): Rope =
var moduleIsEmpty = true
result = getFileHeader(m.config, cfile)
var res = newBuilder(getFileHeader(m.config, cfile))
generateThreadLocalStorage(m)
generateHeaders(m)
result.add(m.s[cfsHeaders])
res.add(extract(m.s[cfsHeaders]))
if m.config.cppCustomNamespace.len > 0:
openNamespaceNim(m.config.cppCustomNamespace, result)
if m.s[cfsFrameDefines].len > 0:
result.add(m.s[cfsFrameDefines])
openNamespaceNim(m.config.cppCustomNamespace, res)
if m.s[cfsFrameDefines].buf.len > 0:
res.add(extract(m.s[cfsFrameDefines]))
for i in cfsForwardTypes..cfsProcs:
if m.s[i].len > 0:
if m.s[i].buf.len > 0:
moduleIsEmpty = false
result.add(m.s[i])
res.add(extract(m.s[i]))
if m.s[cfsInitProc].len > 0:
if m.s[cfsInitProc].buf.len > 0:
moduleIsEmpty = false
result.add(m.s[cfsInitProc])
if m.s[cfsDatInitProc].len > 0 or m.hcrOn:
res.add(extract(m.s[cfsInitProc]))
if m.s[cfsDatInitProc].buf.len > 0 or m.hcrOn:
moduleIsEmpty = false
result.add(m.s[cfsDatInitProc])
res.add(extract(m.s[cfsDatInitProc]))
if m.config.cppCustomNamespace.len > 0:
closeNamespaceNim(result)
closeNamespaceNim(res)
result = extract(res)
if optLineDir in m.config.options:
var srcFileDefs = ""
for fi in 0..m.config.m.fileInfos.high:
@@ -2115,11 +2131,12 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.typeInfoMarker = initTable[SigHash, Rope]()
result.sigConflicts = initCountTable[SigHash]()
result.initProc = newProc(nil, result)
for i in low(result.s)..high(result.s): result.s[i] = newRopeAppender()
for i in low(result.s)..high(result.s): result.s[i] = newBuilder("")
result.initProc.options = initProcOptions(result)
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
result.hcrCreateTypeInfosProc = newBuilder("")
result.dataCache = initNodeTable()
result.typeStack = @[]
result.typeNodesName = getTempName(result)
@@ -2158,7 +2175,7 @@ proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassCont
incl g.generatedHeader.flags, isHeaderFile
proc writeHeader(m: BModule) =
var result = headerTop()
var result = newBuilder(headerTop())
var guard = "__$1__" % [m.filename.splitFile.name.rope]
result.addf("#ifndef $1$n#define $1$n", [guard])
addNimDefines(result, m.config)
@@ -2166,17 +2183,17 @@ proc writeHeader(m: BModule) =
generateThreadLocalStorage(m)
for i in cfsHeaders..cfsProcs:
result.add(m.s[i])
result.add(extract(m.s[i]))
if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders:
openNamespaceNim(m.config.cppCustomNamespace, result)
result.add(m.s[cfsInitProc])
result.add(extract(m.s[cfsInitProc]))
if optGenDynLib in m.config.globalOptions:
result.add("N_LIB_IMPORT ")
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(result)
result.addf("#endif /* $1 */$n", [guard])
if not writeRope(result, m.filename):
if not writeRope(extract(result), m.filename):
rawMessage(m.config, errCannotOpenFile, m.filename.string)
proc getCFile(m: BModule): AbsoluteFile =

View File

@@ -11,7 +11,7 @@
import
ast, ropes, options,
lineinfos, pathutils, modulegraphs
lineinfos, pathutils, modulegraphs, cbuilderbase
import std/[intsets, tables, sets]
@@ -43,12 +43,12 @@ type
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
TCFileSections* = array[TCFileSection, Builder] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
cpsInit, # section for init of variables for C proc
cpsStmts # section of local statements for C proc
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
TCProcSections* = array[TCProcSection, Builder] # represents a generated C proc
BModule* = ref TCGen
BProc* = ref TCProc
TBlock* = object
@@ -161,7 +161,7 @@ type
typeInfoMarkerV2*: TypeCache
initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
hcrCreateTypeInfosProc*: Builder # type info globals are in here when HCR=on
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable
@@ -181,18 +181,18 @@ proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
this.headerFiles.add header
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
proc s*(p: BProc, s: TCProcSection): var Builder {.inline.} =
# section in the current block
result = p.blocks[^1].sections[s]
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
proc procSec*(p: BProc, s: TCProcSection): var Builder {.inline.} =
# top level proc sections
result = p.blocks[0].sections[s]
proc initBlock*(): TBlock =
result = TBlock()
for i in low(result.sections)..high(result.sections):
result.sections[i] = newRopeAppender()
result.sections[i] = newBuilder("")
proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(

View File

@@ -62,6 +62,7 @@
## validated to the server.
##
## ```Nim
## import std/[httpclient]
## var client = newHttpClient()
## var data = newMultipartData()
## data["output"] = "soap12"
@@ -79,6 +80,7 @@
## it, you can pass your own via the `mimeDb` parameter to avoid this.
##
## ```Nim
## import std/[httpclient, mimetypes]
## let mimes = newMimetypes()
## var client = newHttpClient()
## var data = newMultipartData()
@@ -160,7 +162,7 @@
## Example of setting SSL verification parameters in a new client:
##
## ```Nim
## import httpclient
## import std/[net, httpclient]
## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))
## ```
##

View File

@@ -507,12 +507,14 @@ type
nkAsgn,
nkFrom,
nkFromItemPair,
nkJoin,
nkNaturalJoin,
nkUsing,
nkGroup,
nkLimit,
nkOffset,
nkHaving,
nkOrder,
nkJoin,
nkDesc,
nkUnion,
nkIntersect,
@@ -936,18 +938,75 @@ proc parseWhere(p: var SqlParser): SqlNode =
result = newNode(nkWhere)
result.add(parseExpr(p))
proc parseJoinType(p: var SqlParser): SqlNode =
## parse [ INNER ] JOIN | ( LEFT | RIGHT | FULL ) [ OUTER ] JOIN
if isKeyw(p, "inner"):
getTok(p)
eat(p, "join")
return newNode(nkIdent, "inner")
elif isKeyw(p, "join"):
getTok(p)
return newNode(nkIdent, "")
elif isKeyw(p, "left") or isKeyw(p, "full") or isKeyw(p, "right"):
var joinType = newNode(nkIdent, p.tok.literal.toLowerAscii())
getTok(p)
optKeyw(p, "outer")
eat(p, "join")
return joinType
else:
sqlError(p, "join type expected")
proc parseFromItem(p: var SqlParser): SqlNode =
result = newNode(nkFromItemPair)
var expectAs = true
if p.tok.kind == tkParLe:
getTok(p)
var select = parseSelect(p)
result.add(select)
if isKeyw(p, "select"):
result.add(parseSelect(p))
else:
result = parseFromItem(p)
expectAs = false
eat(p, tkParRi)
else:
result.add(parseExpr(p))
if isKeyw(p, "as"):
if expectAs and isKeyw(p, "as"):
getTok(p)
result.add(parseExpr(p))
while true:
if isKeyw(p, "cross"):
var join = newNode(nkJoin)
join.add(newNode(nkIdent, "cross"))
join.add(result)
getTok(p)
eat(p, "join")
join.add(parseFromItem(p))
result = join
elif isKeyw(p, "natural"):
var join = newNode(nkNaturalJoin)
getTok(p)
join.add(parseJoinType(p))
join.add(result)
join.add(parseFromItem(p))
result = join
elif isKeyw(p, "inner") or isKeyw(p, "join") or isKeyw(p, "left") or
iskeyw(p, "full") or isKeyw(p, "right"):
var join = newNode(nkJoin)
join.add(parseJoinType(p))
join.add(result)
join.add(parseFromItem(p))
if isKeyw(p, "on"):
getTok(p)
join.add(parseExpr(p))
elif isKeyw(p, "using"):
getTok(p)
var n = newNode(nkUsing)
parseParIdentList(p, n)
join.add n
else:
sqlError(p, "ON or USING expected")
result = join
else:
break
proc parseIndexDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateIndex)
@@ -1109,19 +1168,6 @@ proc parseSelect(p: var SqlParser): SqlNode =
elif isKeyw(p, "except"):
result.add(newNode(nkExcept))
getTok(p)
if isKeyw(p, "join") or isKeyw(p, "inner") or isKeyw(p, "outer") or isKeyw(p, "cross"):
var join = newNode(nkJoin)
result.add(join)
if isKeyw(p, "join"):
join.add(newNode(nkIdent, ""))
getTok(p)
else:
join.add(newNode(nkIdent, p.tok.literal.toLowerAscii()))
getTok(p)
eat(p, "join")
join.add(parseFromItem(p))
eat(p, "on")
join.add(parseExpr(p))
if isKeyw(p, "limit"):
getTok(p)
var l = newNode(nkLimit)
@@ -1388,6 +1434,30 @@ proc ra(n: SqlNode, s: var SqlWriter) =
of nkFrom:
s.addKeyw("from")
s.addMulti(n)
of nkJoin, nkNaturalJoin:
var joinType = n.sons[0].strVal
if joinType == "":
joinType = "join"
else:
joinType &= " " & "join"
if n.kind == nkNaturalJoin:
joinType = "natural " & joinType
ra(n.sons[1], s)
s.addKeyw(joinType)
# If the right part of the join is not leaf, parenthesize it
if n.sons[2].kind != nkFromItemPair:
s.add('(')
ra(n.sons[2], s)
s.add(')')
else:
ra(n.sons[2], s)
if n.sons.len > 3:
if n.sons[3].kind != nkUsing:
s.addKeyw("on")
ra(n.sons[3], s)
of nkUsing:
s.addKeyw("using")
rs(n, s)
of nkGroup:
s.addKeyw("group by")
s.addMulti(n)
@@ -1403,16 +1473,6 @@ proc ra(n: SqlNode, s: var SqlWriter) =
of nkOrder:
s.addKeyw("order by")
s.addMulti(n)
of nkJoin:
var joinType = n.sons[0].strVal
if joinType == "":
joinType = "join"
else:
joinType &= " " & "join"
s.addKeyw(joinType)
ra(n.sons[1], s)
s.addKeyw("on")
ra(n.sons[2], s)
of nkDesc:
ra(n.sons[0], s)
s.addKeyw("desc")

View File

@@ -159,17 +159,76 @@ INNER JOIN b
ON a.id == b.id
""") == "select id from a inner join b on a.id == b.id;"
doAssert $parseSql("""
# For OUTER joins, LEFT | RIGHT | FULL specifier is not optional
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
OUTER JOIN b
ON a.id == b.id
""") == "select id from a outer join b on a.id == b.id;"
ON a.id = b.id
""")
doAssert $parseSql("""
# For NATURAL JOIN and CROSS JOIN, ON and USING clauses are forbidden
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
CROSS JOIN b
ON a.id == b.id
""") == "select id from a cross join b on a.id == b.id;"
ON a.id = b.id
""")
# JOIN should parse as part of FROM, not after WHERE
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
WHERE a.id IS NOT NULL
INNER JOIN b
ON a.id = b.id
""")
# JOIN should parse as part of FROM, other fromItems may follow
doAssert $parseSql("""
SELECT id
FROM
a JOIN b ON a.id = b.id,
c
""") == "select id from a join b on a.id = b.id, c;"
# LEFT JOIN should parse
doAssert $parseSql("""
SELECT id FROM a
LEFT JOIN b
ON a.id = b.id
""") == "select id from a left join b on a.id = b.id;"
# NATURAL JOIN should parse
doAssert $parseSql("""
SELECT id FROM a
NATURAL JOIN b
""") == "select id from a natural join b;"
# USING should parse
doAssert $parseSql("""
SELECT id FROM a
JOIN b
USING (id)
""") == "select id from a join b using (id );"
# Multiple JOINs should parse
doAssert $parseSql("""
SELECT id FROM a
JOIN b
ON a.id = b.id
LEFT JOIN c
USING (id)
""") == "select id from a join b on a.id = b.id left join c using (id );"
# Parenthesized JOIN expressions should parse
doAssert $parseSql("""
SELECT id
FROM a JOIN (b JOIN c USING (id)) ON a.id = b.id
""") == "select id from a join(b join c using (id )) on a.id = b.id;"
# Left-side parenthesized JOIN expressions should parse
doAssert $parseSql("""
SELECT id
FROM (b JOIN c USING (id)) JOIN a ON a.id = b.id
""") == "select id from b join c using (id ) join a on a.id = b.id;"
doAssert $parseSql("""
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');

View File

@@ -9,7 +9,8 @@
## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim
from stdtest/testutils import enableRemoteNetworking
when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
# badssl tests disabled indefinitely
when false and enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
import httpclient, net, unittest
const expired = "https://expired.badssl.com/"

View File

@@ -19,7 +19,6 @@ from net import newSocket, newContext, wrapSocket, connect, close, Port,
from strutils import contains
const
expired = "https://expired.badssl.com/"
good = "https://google.com/"
@@ -56,12 +55,13 @@ suite "SSL certificate check":
var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
ctx.wrapSocket(sock)
checkpoint("Socket created")
try:
sock.connect("expired.badssl.com", 443.Port)
fail()
except:
sock.close
check getCurrentExceptionMsg().contains("certificate verify failed")
when false: # badssl tests disabled indefinitely
try:
sock.connect("expired.badssl.com", 443.Port)
fail()
except:
sock.close
check getCurrentExceptionMsg().contains("certificate verify failed")
elif existsEnv("SSL_CERT_DIR"):
var sock = newSocket()

View File

@@ -33,7 +33,8 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win
CertTest = tuple[url:string, category:Category, desc: string]
# badssl certs sometimes expire, set to false when that happens
when true:
# badssl now disabled indefinitely
when false:
const certificate_tests: array[0..54, CertTest] = [
("https://wrong.host.badssl.com/", bad, "wrong.host"),
("https://captive-portal.badssl.com/", bad, "captive-portal"),
@@ -197,7 +198,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win
type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string]
# badssl certs sometimes expire, set to false when that happens
when true:
when false:
const net_tests:array[0..3, NetSocketTest] = [
("imap.gmail.com", 993.Port, good, "IMAP"),
("wrong.host.badssl.com", 443.Port, bad, "wrong.host"),