mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-17 21:12:42 +00:00
Merge branch 'devel' into underscore-tuple-unpack
Conflicts: compiler/semstmts.nim
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -296,6 +296,7 @@ const
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||
sfGoto* = sfOverriden # var is used for 'goto' code generation
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
@@ -472,7 +473,7 @@ type
|
||||
# T and I here can bind to both typedesc and static types
|
||||
# before this is determined, we'll consider them to be a
|
||||
# wildcard type.
|
||||
tfGuarded # guarded pointer
|
||||
tfHasAsgn # type has overloaded assignment operator
|
||||
tfBorrowDot # distinct type borrows '.'
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
@@ -529,19 +530,20 @@ type
|
||||
TMagic* = enum # symbols that require compiler magic:
|
||||
mNone,
|
||||
mDefined, mDefinedInScope, mCompiles,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
mGCunref,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
mGCref, mGCunref,
|
||||
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mSucc, mPred,
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
@@ -550,7 +552,7 @@ type
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
@@ -589,11 +591,12 @@ type
|
||||
const
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
@@ -602,7 +605,7 @@ const
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
@@ -685,8 +688,8 @@ type
|
||||
s*: TStorageLoc
|
||||
flags*: TLocFlags # location's flags
|
||||
t*: PType # type of location
|
||||
r*: PRope # rope value of location (code generators)
|
||||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||
r*: Rope # rope value of location (code generators)
|
||||
heapRoot*: Rope # keeps track of the enclosing heap object that
|
||||
# owns this location (required by GC algorithms
|
||||
# employing heap snapshots or sliding views)
|
||||
|
||||
@@ -698,7 +701,7 @@ type
|
||||
kind*: TLibKind
|
||||
generated*: bool # needed for the backends:
|
||||
isOverriden*: bool
|
||||
name*: PRope
|
||||
name*: Rope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
TInstantiation* = object
|
||||
@@ -728,7 +731,8 @@ type
|
||||
typScope*: PScope
|
||||
of routineKinds:
|
||||
procInstCache*: seq[PInstantiation]
|
||||
scope*: PScope # the scope where the proc was defined
|
||||
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
|
||||
#scope*: PScope # the scope where the proc was defined
|
||||
of skModule:
|
||||
# modules keep track of the generic symbols they use from other modules.
|
||||
# this is because in incremental compilation, when a module is about to
|
||||
@@ -794,8 +798,8 @@ type
|
||||
# for enum types a list of symbols
|
||||
# for tyInt it can be the int literal
|
||||
# for procs and tyGenericBody, it's the
|
||||
# the body of the user-defined type class
|
||||
# formal param list
|
||||
# for concepts, the concept body
|
||||
# else: unused
|
||||
owner*: PSym # the 'owner' of the type
|
||||
sym*: PSym # types have the sym associated with them
|
||||
@@ -804,6 +808,7 @@ type
|
||||
# mean that there is no destructor.
|
||||
# see instantiateDestructor in semdestruct.nim
|
||||
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||
assignment*: PSym # overriden '=' operator
|
||||
size*: BiggestInt # the size of the type in bytes
|
||||
# -1 means that the size is unkwown
|
||||
align*: int16 # the type's alignment requirements
|
||||
@@ -1168,7 +1173,9 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
result.lockLevel = UnspecifiedLockLevel
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
#if result.id == 92231:
|
||||
# echo "KNID ", kind
|
||||
# writeStackTrace()
|
||||
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
@@ -1218,6 +1225,7 @@ proc assignType*(dest, src: PType) =
|
||||
dest.align = src.align
|
||||
dest.destructor = src.destructor
|
||||
dest.deepCopy = src.deepCopy
|
||||
dest.assignment = src.assignment
|
||||
dest.lockLevel = src.lockLevel
|
||||
# this fixes 'type TLock = TSysLock':
|
||||
if src.sym != nil:
|
||||
@@ -1314,6 +1322,13 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
result = t
|
||||
while result.kind in kinds: result = lastSon(result)
|
||||
|
||||
proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
|
||||
## same as skipTypes but handles 'nil'
|
||||
result = t
|
||||
while result != nil and result.kind in kinds:
|
||||
if result.len == 0: return nil
|
||||
result = lastSon(result)
|
||||
|
||||
proc isGCedMem*(t: PType): bool {.inline.} =
|
||||
result = t.kind in {tyString, tyRef, tySequence} or
|
||||
t.kind == tyProc and t.callConv == ccClosure
|
||||
@@ -1334,6 +1349,13 @@ proc propagateToOwner*(owner, elem: PType) =
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
if tfHasAsgn in elem.flags:
|
||||
let o2 = elem.skipTypes({tyGenericInst})
|
||||
if o2.kind in {tyTuple, tyObject, tyArray, tyArrayConstr,
|
||||
tySequence, tySet, tyDistinct}:
|
||||
o2.flags.incl tfHasAsgn
|
||||
owner.flags.incl tfHasAsgn
|
||||
|
||||
if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
|
||||
tyGenericInvocation}:
|
||||
let elemB = elem.skipTypes({tyGenericInst})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -243,24 +243,24 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
var oldLen = result.len
|
||||
result.add('<')
|
||||
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
|
||||
if loc.s != low(loc.s):
|
||||
if loc.s != low(loc.s):
|
||||
add(result, '*')
|
||||
encodeVInt(ord(loc.s), result)
|
||||
if loc.flags != {}:
|
||||
if loc.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](loc.flags), result)
|
||||
if loc.t != nil:
|
||||
add(result, '^')
|
||||
encodeVInt(cast[int32](loc.t.id), result)
|
||||
pushType(w, loc.t)
|
||||
if loc.r != nil:
|
||||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr(ropeToStr(loc.r), result)
|
||||
if loc.a != 0:
|
||||
encodeStr($loc.r, result)
|
||||
if loc.a != 0:
|
||||
add(result, '?')
|
||||
encodeVInt(loc.a, result)
|
||||
if oldLen + 1 == result.len:
|
||||
@@ -317,7 +317,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
encodeStr(ropeToStr(lib.name), result)
|
||||
encodeStr($lib.name, result)
|
||||
add(result, '|')
|
||||
encodeNode(w, info, lib.path, result)
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ proc hasNoInit(call: PNode): bool {.inline.} =
|
||||
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
|
||||
|
||||
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
callee, params: PRope) =
|
||||
var pl = con(callee, ~"(", params)
|
||||
callee, params: Rope) =
|
||||
var pl = callee & ~"(" & params
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(typ.sons[0]):
|
||||
if params != nil: pl.app(~", ")
|
||||
if params != nil: pl.add(~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -33,18 +33,18 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
resetLoc(p, d)
|
||||
app(pl, addrLoc(d))
|
||||
app(pl, ~");$n")
|
||||
add(pl, addrLoc(d))
|
||||
add(pl, ~");$n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
app(pl, ~");$n")
|
||||
add(pl, addrLoc(tmp))
|
||||
add(pl, ~");$n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~")")
|
||||
add(pl, ~")")
|
||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
@@ -60,7 +60,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~");$n")
|
||||
add(pl, ~");$n")
|
||||
line(p, cpsStmts, pl)
|
||||
|
||||
proc isInCurrentFrame(p: BProc, n: PNode): bool =
|
||||
@@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
|
||||
result = isInCurrentFrame(p, n.sons[0])
|
||||
else: discard
|
||||
|
||||
proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||
var a: TLoc
|
||||
|
||||
let q = skipConv(n)
|
||||
@@ -104,28 +104,28 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
else:
|
||||
"$1->data+($2), ($3)-($2)+1"
|
||||
else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
|
||||
result = ropef(fmt, [rdLoc(a), rdLoc(b), rdLoc(c)])
|
||||
result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
|
||||
else:
|
||||
initLocExpr(p, n, a)
|
||||
case skipTypes(a.t, abstractVar).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = ropef("$1, $1Len0", [rdLoc(a)])
|
||||
result = "$1, $1Len0" % [rdLoc(a)]
|
||||
of tyString, tySequence:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||
not compileToCpp(p.module):
|
||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
||||
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
|
||||
else:
|
||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
||||
result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
|
||||
of tyArray, tyArrayConstr:
|
||||
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
|
||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
|
||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} =
|
||||
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
result = ropef("$1->data", [a.rdLoc])
|
||||
result = "$1->data" % [a.rdLoc]
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
result = genArgStringToCString(p, n)
|
||||
@@ -151,7 +151,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
|
||||
initLocExprSingleUse(p, n, a)
|
||||
result = rdLoc(a)
|
||||
|
||||
proc genArgNoParam(p: BProc, n: PNode): PRope =
|
||||
proc genArgNoParam(p: BProc, n: PNode): Rope =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
result = genArgStringToCString(p, n)
|
||||
@@ -163,7 +163,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
# this is a hotspot in the compiler
|
||||
initLocExpr(p, ri.sons[0], op)
|
||||
var params: PRope
|
||||
var params: Rope
|
||||
# getUniqueType() is too expensive here:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -171,27 +171,27 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var length = sonsLen(ri)
|
||||
for i in countup(1, length - 1):
|
||||
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||
if params != nil: app(params, ~", ")
|
||||
if params != nil: add(params, ~", ")
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
app(params, genArgNoParam(p, ri.sons[i]))
|
||||
add(params, genArgNoParam(p, ri.sons[i]))
|
||||
fixupCall(p, le, ri, d, op.r, params)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
||||
proc getRawProcType(p: BProc, t: PType): PRope =
|
||||
proc getRawProcType(p: BProc, t: PType): Rope =
|
||||
result = getClosureType(p.module, t, clHalf)
|
||||
|
||||
proc addComma(r: PRope): PRope =
|
||||
result = if r == nil: r else: con(r, ~", ")
|
||||
proc addComma(r: Rope): Rope =
|
||||
result = if r == nil: r else: r & ~", "
|
||||
|
||||
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
|
||||
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
|
||||
var op: TLoc
|
||||
initLocExpr(p, ri.sons[0], op)
|
||||
var pl: PRope
|
||||
var pl: Rope
|
||||
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
@@ -201,19 +201,19 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
app(pl, genArgNoParam(p, ri.sons[i]))
|
||||
if i < length - 1: app(pl, ~", ")
|
||||
add(pl, genArgNoParam(p, ri.sons[i]))
|
||||
if i < length - 1: add(pl, ~", ")
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||
lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
|
||||
|
||||
let rawProc = getRawProcType(p, typ)
|
||||
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(typ.sons[0]):
|
||||
if sonsLen(ri) > 1: app(pl, ~", ")
|
||||
if sonsLen(ri) > 1: add(pl, ~", ")
|
||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
||||
# Great, we can use 'd':
|
||||
@@ -222,12 +222,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
|
||||
# reset before pass as 'result' var:
|
||||
resetLoc(p, d)
|
||||
app(pl, addrLoc(d))
|
||||
add(pl, addrLoc(d))
|
||||
genCallPattern()
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
add(pl, addrLoc(tmp))
|
||||
genCallPattern()
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
@@ -235,12 +235,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
|
||||
list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
genCallPattern()
|
||||
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
if ri.sons[i].typ.isCompileTimeOnly:
|
||||
result = nil
|
||||
elif i < sonsLen(typ):
|
||||
@@ -291,7 +291,25 @@ y.v() --> y.v() is correct
|
||||
|
||||
"""
|
||||
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||
proc skipAddrDeref(node: PNode): PNode =
|
||||
var n = node
|
||||
var isAddr = false
|
||||
case n.kind
|
||||
of nkAddr, nkHiddenAddr:
|
||||
n = n.sons[0]
|
||||
isAddr = true
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
n = n.sons[0]
|
||||
else: return n
|
||||
if n.kind == nkObjDownConv: n = n.sons[0]
|
||||
if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
|
||||
result = n.sons[0]
|
||||
elif n.kind in {nkAddr, nkHiddenAddr}:
|
||||
result = n.sons[0]
|
||||
else:
|
||||
result = node
|
||||
|
||||
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
# for better or worse c2nim translates the 'this' argument to a 'var T'.
|
||||
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||
# for convenience.
|
||||
@@ -301,83 +319,84 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||
# skip the deref:
|
||||
var ri = ri[i]
|
||||
while ri.kind == nkObjDownConv: ri = ri[0]
|
||||
if typ.sons[i].kind == tyVar:
|
||||
let t = typ.sons[i].skipTypes({tyGenericInst})
|
||||
if t.kind == tyVar:
|
||||
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
|
||||
if x.typ.kind == tyPtr:
|
||||
result = genArgNoParam(p, x)
|
||||
result.app("->")
|
||||
result.add("->")
|
||||
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
|
||||
result = genArgNoParam(p, x[0])
|
||||
result.app("->")
|
||||
result.add("->")
|
||||
else:
|
||||
result = genArgNoParam(p, x)
|
||||
result.app(".")
|
||||
elif typ.sons[i].kind == tyPtr:
|
||||
result.add(".")
|
||||
elif t.kind == tyPtr:
|
||||
if ri.kind in {nkAddr, nkHiddenAddr}:
|
||||
result = genArgNoParam(p, ri[0])
|
||||
result.app(".")
|
||||
result.add(".")
|
||||
else:
|
||||
result = genArgNoParam(p, ri)
|
||||
result.app("->")
|
||||
result.add("->")
|
||||
else:
|
||||
ri = skipAddrDeref(ri)
|
||||
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
|
||||
result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
|
||||
result.app(".")
|
||||
result.add(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
|
||||
var i = 0
|
||||
var j = 1
|
||||
while i < pat.len:
|
||||
case pat[i]
|
||||
of '@':
|
||||
if j < ri.len:
|
||||
result.app genOtherArg(p, ri, j, typ)
|
||||
result.add genOtherArg(p, ri, j, typ)
|
||||
for k in j+1 .. < ri.len:
|
||||
result.app(~", ")
|
||||
result.app genOtherArg(p, ri, k, typ)
|
||||
result.add(~", ")
|
||||
result.add genOtherArg(p, ri, k, typ)
|
||||
inc i
|
||||
of '#':
|
||||
if pat[i+1] in {'+', '@'}:
|
||||
let ri = ri[j]
|
||||
if ri.kind in nkCallKinds:
|
||||
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||
result.app(~"(")
|
||||
if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
|
||||
result.add(~"(")
|
||||
if 1 < ri.len:
|
||||
result.app genOtherArg(p, ri, 1, typ)
|
||||
result.add genOtherArg(p, ri, 1, typ)
|
||||
for k in j+1 .. < ri.len:
|
||||
result.app(~", ")
|
||||
result.app genOtherArg(p, ri, k, typ)
|
||||
result.app(~")")
|
||||
result.add(~", ")
|
||||
result.add genOtherArg(p, ri, k, typ)
|
||||
result.add(~")")
|
||||
else:
|
||||
localError(ri.info, "call expression expected for C++ pattern")
|
||||
inc i
|
||||
elif pat[i+1] == '.':
|
||||
result.app genThisArg(p, ri, j, typ)
|
||||
result.add genThisArg(p, ri, j, typ)
|
||||
inc i
|
||||
elif pat[i+1] == '[':
|
||||
var arg = ri.sons[j].skipAddrDeref
|
||||
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
|
||||
result.add genArgNoParam(p, arg)
|
||||
#result.add debugTree(arg, 0, 10)
|
||||
else:
|
||||
result.app genOtherArg(p, ri, j, typ)
|
||||
result.add genOtherArg(p, ri, j, typ)
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
inc i
|
||||
let stars = i
|
||||
while pat[i] == '*': inc i
|
||||
if pat[i] in Digits:
|
||||
let j = pat[i].ord - '0'.ord
|
||||
var t = typ.sons[j]
|
||||
for k in 1..i-stars:
|
||||
if t != nil and t.len > 0:
|
||||
t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
|
||||
if t == nil: result.app(~"void")
|
||||
else: result.app(getTypeDesc(p.module, t))
|
||||
inc i
|
||||
var idx, stars: int
|
||||
if scanCppGenericSlot(pat, i, idx, stars):
|
||||
var t = resolveStarsInCppType(typ, idx, stars)
|
||||
if t == nil: result.add(~"void")
|
||||
else: result.add(getTypeDesc(p.module, t))
|
||||
else:
|
||||
let start = i
|
||||
while i < pat.len:
|
||||
if pat[i] notin {'@', '#', '\''}: inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
app(result, substr(pat, start, i - 1))
|
||||
add(result, substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op, a: TLoc
|
||||
@@ -387,7 +406,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
# don't call 'ropeToStr' here for efficiency:
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert pat != nil
|
||||
if pat.contains({'#', '(', '@', '\''}):
|
||||
@@ -410,19 +429,19 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~";$n")
|
||||
add(pl, ~";$n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var pl: PRope = nil
|
||||
var pl: Rope = nil
|
||||
#var param = typ.n.sons[1].sym
|
||||
if 1 < ri.len:
|
||||
app(pl, genThisArg(p, ri, 1, typ))
|
||||
app(pl, op.r)
|
||||
var params: PRope
|
||||
add(pl, genThisArg(p, ri, 1, typ))
|
||||
add(pl, op.r)
|
||||
var params: Rope
|
||||
for i in countup(2, length - 1):
|
||||
if params != nil: params.app(~", ")
|
||||
if params != nil: params.add(~", ")
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
app(params, genOtherArg(p, ri, i, typ))
|
||||
add(params, genOtherArg(p, ri, i, typ))
|
||||
fixupCall(p, le, ri, d, pl, params)
|
||||
|
||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
@@ -436,55 +455,55 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
var length = sonsLen(ri)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
|
||||
# don't call 'ropeToStr' here for efficiency:
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert pat != nil
|
||||
var start = 3
|
||||
if ' ' in pat:
|
||||
start = 1
|
||||
app(pl, op.r)
|
||||
add(pl, op.r)
|
||||
if length > 1:
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
add(pl, ~": ")
|
||||
add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
start = 2
|
||||
else:
|
||||
if length > 1:
|
||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
app(pl, ~" ")
|
||||
app(pl, op.r)
|
||||
add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
add(pl, ~" ")
|
||||
add(pl, op.r)
|
||||
if length > 2:
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
|
||||
add(pl, ~": ")
|
||||
add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
|
||||
for i in countup(start, length-1):
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if i >= sonsLen(typ):
|
||||
internalError(ri.info, "varargs for objective C method?")
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
var param = typ.n.sons[i].sym
|
||||
app(pl, ~" ")
|
||||
app(pl, param.name.s)
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[i], param, ri))
|
||||
add(pl, ~" ")
|
||||
add(pl, param.name.s)
|
||||
add(pl, ~": ")
|
||||
add(pl, genArg(p, ri.sons[i], param, ri))
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(typ.sons[0]):
|
||||
if sonsLen(ri) > 1: app(pl, ~" ")
|
||||
if sonsLen(ri) > 1: add(pl, ~" ")
|
||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||
if d.k in {locTemp, locNone}:
|
||||
# We already got a temp. Great, special case it:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
|
||||
app(pl, ~"Result: ")
|
||||
app(pl, addrLoc(d))
|
||||
app(pl, ~"];$n")
|
||||
add(pl, ~"Result: ")
|
||||
add(pl, addrLoc(d))
|
||||
add(pl, ~"];$n")
|
||||
line(p, cpsStmts, pl)
|
||||
else:
|
||||
var tmp: TLoc
|
||||
getTemp(p, typ.sons[0], tmp, needsInit=true)
|
||||
app(pl, addrLoc(tmp))
|
||||
app(pl, ~"];$n")
|
||||
add(pl, addrLoc(tmp))
|
||||
add(pl, ~"];$n")
|
||||
line(p, cpsStmts, pl)
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~"]")
|
||||
add(pl, ~"]")
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
@@ -492,7 +511,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~"];$n")
|
||||
add(pl, ~"];$n")
|
||||
line(p, cpsStmts, pl)
|
||||
|
||||
proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,29 +45,29 @@ const
|
||||
]
|
||||
NimMergeEndMark = "/*\tNIM_merge_END:*/"
|
||||
|
||||
proc genSectionStart*(fs: TCFileSection): PRope =
|
||||
proc genSectionStart*(fs: TCFileSection): Rope =
|
||||
if compilationCachePresent:
|
||||
result = toRope(tnl)
|
||||
app(result, "/*\t")
|
||||
app(result, CFileSectionNames[fs])
|
||||
app(result, ":*/")
|
||||
app(result, tnl)
|
||||
result = rope(tnl)
|
||||
add(result, "/*\t")
|
||||
add(result, CFileSectionNames[fs])
|
||||
add(result, ":*/")
|
||||
add(result, tnl)
|
||||
|
||||
proc genSectionEnd*(fs: TCFileSection): PRope =
|
||||
proc genSectionEnd*(fs: TCFileSection): Rope =
|
||||
if compilationCachePresent:
|
||||
result = toRope(NimMergeEndMark & tnl)
|
||||
result = rope(NimMergeEndMark & tnl)
|
||||
|
||||
proc genSectionStart*(ps: TCProcSection): PRope =
|
||||
proc genSectionStart*(ps: TCProcSection): Rope =
|
||||
if compilationCachePresent:
|
||||
result = toRope(tnl)
|
||||
app(result, "/*\t")
|
||||
app(result, CProcSectionNames[ps])
|
||||
app(result, ":*/")
|
||||
app(result, tnl)
|
||||
result = rope(tnl)
|
||||
add(result, "/*\t")
|
||||
add(result, CProcSectionNames[ps])
|
||||
add(result, ":*/")
|
||||
add(result, tnl)
|
||||
|
||||
proc genSectionEnd*(ps: TCProcSection): PRope =
|
||||
proc genSectionEnd*(ps: TCProcSection): Rope =
|
||||
if compilationCachePresent:
|
||||
result = toRope(NimMergeEndMark & tnl)
|
||||
result = rope(NimMergeEndMark & tnl)
|
||||
|
||||
proc writeTypeCache(a: TIdTable, s: var string) =
|
||||
var i = 0
|
||||
@@ -79,7 +79,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
|
||||
s.add(' ')
|
||||
encodeVInt(id, s)
|
||||
s.add(':')
|
||||
encodeStr(PRope(value).ropeToStr, s)
|
||||
encodeStr($Rope(value), s)
|
||||
inc i
|
||||
s.add('}')
|
||||
|
||||
@@ -95,7 +95,7 @@ proc writeIntSet(a: IntSet, s: var string) =
|
||||
inc i
|
||||
s.add('}')
|
||||
|
||||
proc genMergeInfo*(m: BModule): PRope =
|
||||
proc genMergeInfo*(m: BModule): Rope =
|
||||
if optSymbolFiles notin gGlobalOptions: return nil
|
||||
var s = "/*\tNIM_merge_INFO:"
|
||||
s.add(tnl)
|
||||
@@ -111,7 +111,7 @@ proc genMergeInfo*(m: BModule): PRope =
|
||||
encodeVInt(ord(m.frameDeclared), s)
|
||||
s.add(tnl)
|
||||
s.add("*/")
|
||||
result = s.toRope
|
||||
result = s.rope
|
||||
|
||||
template `^`(pos: int): expr = L.buf[pos]
|
||||
|
||||
@@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
|
||||
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
|
||||
result = s == NimMergeEndMark.len
|
||||
|
||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
proc readVerbatimSection(L: var TBaseLexer): Rope =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
var r = newStringOfCap(30_000)
|
||||
@@ -169,7 +169,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||
r.add(buf[pos])
|
||||
inc pos
|
||||
L.bufpos = pos
|
||||
result = r.toRope
|
||||
result = r.rope
|
||||
|
||||
proc readKey(L: var TBaseLexer, result: var string) =
|
||||
var pos = L.bufpos
|
||||
@@ -197,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
|
||||
# XXX little hack: we create a "fake" type object with the correct Id
|
||||
# better would be to adapt the data structure to not even store the
|
||||
# object as key, but only the Id
|
||||
idTablePut(result, newFakeType(key), value.toRope)
|
||||
idTablePut(result, newFakeType(key), value.rope)
|
||||
inc L.bufpos
|
||||
|
||||
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
|
||||
@@ -280,11 +280,11 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||
proc mergeRequired*(m: BModule): bool =
|
||||
for i in cfsHeaders..cfsProcs:
|
||||
if m.s[i] != nil:
|
||||
#echo "not empty: ", i, " ", ropeToStr(m.s[i])
|
||||
#echo "not empty: ", i, " ", m.s[i]
|
||||
return true
|
||||
for i in low(TCProcSection)..high(TCProcSection):
|
||||
if m.initProc.s(i) != nil:
|
||||
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
|
||||
#echo "not empty: ", i, " ", m.initProc.s[i]
|
||||
return true
|
||||
|
||||
proc mergeFiles*(cfilename: string, m: BModule) =
|
||||
@@ -293,6 +293,6 @@ proc mergeFiles*(cfilename: string, m: BModule) =
|
||||
readMergeSections(cfilename, old)
|
||||
# do the merge; old section before new section:
|
||||
for i in low(TCFileSection)..high(TCFileSection):
|
||||
m.s[i] = con(old.f[i], m.s[i])
|
||||
m.s[i] = old.f[i] & m.s[i]
|
||||
for i in low(TCProcSection)..high(TCProcSection):
|
||||
m.initProc.s(i) = con(old.p[i], m.initProc.s(i))
|
||||
m.initProc.s(i) = old.p[i] & m.initProc.s(i)
|
||||
|
||||
@@ -61,11 +61,10 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
|
||||
initLoc(field, locExpr, t.sons[i], tup.s)
|
||||
if t.kind == tyTuple:
|
||||
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
|
||||
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||
else:
|
||||
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
|
||||
field.r = ropef("$1.$2",
|
||||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
|
||||
@@ -86,8 +85,8 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
else:
|
||||
expr(p, ri, a)
|
||||
|
||||
proc startBlock(p: BProc, start: TFormatStr = "{$n",
|
||||
args: varargs[PRope]): int {.discardable.} =
|
||||
proc startBlock(p: BProc, start: FormatStr = "{$n",
|
||||
args: varargs[Rope]): int {.discardable.} =
|
||||
lineCg(p, cpsStmts, start, args)
|
||||
inc(p.labels)
|
||||
result = len(p.blocks)
|
||||
@@ -96,21 +95,21 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
|
||||
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
|
||||
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
|
||||
|
||||
proc assignLabel(b: var TBlock): PRope {.inline.} =
|
||||
b.label = con("LA", b.id.toRope)
|
||||
proc assignLabel(b: var TBlock): Rope {.inline.} =
|
||||
b.label = "LA" & b.id.rope
|
||||
result = b.label
|
||||
|
||||
proc blockBody(b: var TBlock): PRope =
|
||||
proc blockBody(b: var TBlock): Rope =
|
||||
result = b.sections[cpsLocals]
|
||||
if b.frameLen > 0:
|
||||
result.appf("F.len+=$1;$n", b.frameLen.toRope)
|
||||
result.app(b.sections[cpsInit])
|
||||
result.app(b.sections[cpsStmts])
|
||||
result.addf("F.len+=$1;$n", [b.frameLen.rope])
|
||||
result.add(b.sections[cpsInit])
|
||||
result.add(b.sections[cpsStmts])
|
||||
|
||||
proc endBlock(p: BProc, blockEnd: PRope) =
|
||||
proc endBlock(p: BProc, blockEnd: Rope) =
|
||||
let topBlock = p.blocks.len-1
|
||||
# the block is merged into the parent block
|
||||
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
||||
add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
|
||||
setLen(p.blocks, topBlock)
|
||||
# this is done after the block is popped so $n is
|
||||
# properly indented when pretty printing is enabled
|
||||
@@ -124,7 +123,7 @@ proc endBlock(p: BProc) =
|
||||
~"}$n"
|
||||
let frameLen = p.blocks[topBlock].frameLen
|
||||
if frameLen > 0:
|
||||
blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
|
||||
blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
|
||||
endBlock(p, blockEnd)
|
||||
|
||||
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||
@@ -145,7 +144,7 @@ template preserveBreakIdx(body: stmt): stmt {.immediate.} =
|
||||
proc genState(p: BProc, n: PNode) =
|
||||
internalAssert n.len == 1 and n.sons[0].kind == nkIntLit
|
||||
let idx = n.sons[0].intVal
|
||||
linefmt(p, cpsStmts, "STATE$1: ;$n", idx.toRope)
|
||||
linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope)
|
||||
|
||||
proc genGotoState(p: BProc, n: PNode) =
|
||||
# we resist the temptation to translate it into duff's device as it later
|
||||
@@ -159,7 +158,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
p.beforeRetNeeded = true
|
||||
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
|
||||
for i in 0 .. lastOrd(n.sons[0].typ):
|
||||
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
|
||||
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
|
||||
proc genBreakState(p: BProc, n: PNode) =
|
||||
@@ -176,9 +175,18 @@ proc genBreakState(p: BProc, n: PNode) =
|
||||
|
||||
proc genVarPrototypeAux(m: BModule, sym: PSym)
|
||||
|
||||
proc genGotoVar(p: BProc; value: PNode) =
|
||||
if value.kind notin {nkCharLit..nkUInt64Lit}:
|
||||
localError(value.info, "'goto' target must be a literal value")
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
||||
|
||||
proc genSingleVar(p: BProc, a: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if sfCompileTime in v.flags: return
|
||||
if {sfCompileTime, sfGoto} * v.flags != {}:
|
||||
# translate 'var state {.goto.} = X' into 'goto LX':
|
||||
if sfGoto in v.flags: genGotoVar(p, a.sons[2])
|
||||
return
|
||||
var targetProc = p
|
||||
if sfGlobal in v.flags:
|
||||
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
|
||||
@@ -214,17 +222,17 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
var tmp: TLoc
|
||||
if value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
sfConstructor in value[0].sym.flags:
|
||||
var params: PRope
|
||||
var params: Rope
|
||||
let typ = skipTypes(value.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
for i in 1.. <value.len:
|
||||
if params != nil: params.app(~", ")
|
||||
if params != nil: params.add(~", ")
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
app(params, genOtherArg(p, value, i, typ))
|
||||
lineF(p, cpsStmts, "$#($#);$n", decl, params)
|
||||
add(params, genOtherArg(p, value, i, typ))
|
||||
lineF(p, cpsStmts, "$#($#);$n", [decl, params])
|
||||
else:
|
||||
initLocExprSingleUse(p, value, tmp)
|
||||
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
|
||||
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
|
||||
return
|
||||
assignLocalVar(p, v)
|
||||
initLocalVar(p, v, imm)
|
||||
@@ -298,9 +306,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
when not newScopeForIf: startBlock(p)
|
||||
if p.module.compileToCpp:
|
||||
# avoid "jump to label crosses initialization" error:
|
||||
app(p.s(cpsStmts), "{")
|
||||
add(p.s(cpsStmts), "{")
|
||||
expr(p, it.sons[1], d)
|
||||
app(p.s(cpsStmts), "}")
|
||||
add(p.s(cpsStmts), "}")
|
||||
else:
|
||||
expr(p, it.sons[1], d)
|
||||
endBlock(p)
|
||||
@@ -366,6 +374,19 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
||||
lineF(p, cpsStmts, "goto BeforeRet;$n", [])
|
||||
|
||||
proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
for i in 1 .. <caseStmt.len:
|
||||
startBlock(p)
|
||||
let it = caseStmt.sons[i]
|
||||
for j in 0 .. it.len-2:
|
||||
if it.sons[j].kind == nkRange:
|
||||
localError(it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
|
||||
genStmts(p, it.lastSon)
|
||||
endBlock(p)
|
||||
|
||||
proc genComputedGoto(p: BProc; n: PNode) =
|
||||
# first pass: Generate array of computed labels:
|
||||
var casePos = -1
|
||||
@@ -389,11 +410,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
localError(n.info, "no case statement found for computed goto"); return
|
||||
var id = p.labels+1
|
||||
inc p.labels, arraySize+1
|
||||
let tmp = ropef("TMP$1", id.toRope)
|
||||
var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope)
|
||||
let tmp = "TMP$1" % [id.rope]
|
||||
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
|
||||
for i in 1..arraySize-1:
|
||||
gotoArray.appf("&&TMP$#, ", (id+i).toRope)
|
||||
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
|
||||
gotoArray.addf("&&TMP$#, ", [(id+i).rope])
|
||||
gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
|
||||
line(p, cpsLocals, gotoArray)
|
||||
|
||||
let topBlock = p.blocks.len-1
|
||||
@@ -407,13 +428,13 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
|
||||
let tailA = p.blocks[topBlock].sections[cpsStmts]
|
||||
|
||||
p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA)
|
||||
p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
|
||||
|
||||
let caseStmt = n.sons[casePos]
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt.sons[0], a)
|
||||
# first goto:
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
|
||||
for i in 1 .. <caseStmt.len:
|
||||
startBlock(p)
|
||||
@@ -423,16 +444,16 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
localError(it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
|
||||
lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
|
||||
genStmts(p, it.lastSon)
|
||||
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
|
||||
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
|
||||
app(p.s(cpsStmts), tailB)
|
||||
app(p.s(cpsStmts), tailA)
|
||||
add(p.s(cpsStmts), tailB)
|
||||
add(p.s(cpsStmts), tailA)
|
||||
|
||||
var a: TLoc
|
||||
initLocExpr(p, caseStmt.sons[0], a)
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
endBlock(p)
|
||||
|
||||
proc genWhileStmt(p: BProc, t: PNode) =
|
||||
@@ -498,9 +519,9 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
|
||||
lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
|
||||
"for ($1 = $2; $1 <= $3; ++$1)",
|
||||
forLoopVar.loc.rdLoc,
|
||||
[forLoopVar.loc.rdLoc,
|
||||
rangeA.rdLoc, rangeB.rdLoc,
|
||||
call.sons[3].getStr.toRope)
|
||||
call.sons[3].getStr.rope])
|
||||
|
||||
p.breakIdx = startBlock(p)
|
||||
p.blocks[p.breakIdx].isLoop = true
|
||||
@@ -560,7 +581,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n")
|
||||
|
||||
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
|
||||
rangeFormat, eqFormat: FormatStr, labl: TLabel) =
|
||||
var
|
||||
x, y: TLoc
|
||||
var length = sonsLen(b)
|
||||
@@ -578,7 +599,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
labId, until: int): TLabel =
|
||||
var lend = getLabel(p)
|
||||
for i in 1..until:
|
||||
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
|
||||
lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
var length = sonsLen(t.sons[i])
|
||||
exprBlock(p, t.sons[i].sons[length - 1], d)
|
||||
@@ -588,7 +609,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
result = lend
|
||||
|
||||
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr,
|
||||
rangeFormat, eqFormat: FormatStr,
|
||||
until: int, a: TLoc): TLabel =
|
||||
# generate a C-if statement for a Nim case statement
|
||||
var labId = p.labels
|
||||
@@ -596,27 +617,27 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
inc(p.labels)
|
||||
if t.sons[i].kind == nkOfBranch: # else statement
|
||||
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
||||
con("LA", toRope(p.labels)))
|
||||
"LA" & rope(p.labels))
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
|
||||
if until < t.len-1:
|
||||
inc(p.labels)
|
||||
var gotoTarget = p.labels
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(gotoTarget)])
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
|
||||
result = genCaseSecondPass(p, t, d, labId, until)
|
||||
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)])
|
||||
lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
|
||||
else:
|
||||
result = genCaseSecondPass(p, t, d, labId, until)
|
||||
|
||||
proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr) =
|
||||
rangeFormat, eqFormat: FormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
branches: var openArray[PRope]) =
|
||||
branches: var openArray[Rope]) =
|
||||
var x: TLoc
|
||||
var length = sonsLen(b)
|
||||
for i in countup(0, length - 2):
|
||||
@@ -634,7 +655,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
|
||||
if strings > stringCaseThreshold:
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[PRope]
|
||||
var branches: seq[Rope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||
@@ -642,21 +663,21 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
inc(p.labels)
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)),
|
||||
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
|
||||
branches)
|
||||
else:
|
||||
# else statement: nothing to do yet
|
||||
# but we reserved a label, which we use later
|
||||
discard
|
||||
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
|
||||
rdLoc(a), toRope(bitMask))
|
||||
rdLoc(a), rope(bitMask))
|
||||
for j in countup(0, high(branches)):
|
||||
if branches[j] != nil:
|
||||
lineF(p, cpsStmts, "case $1: $n$2break;$n",
|
||||
[intLiteral(j), branches[j]])
|
||||
lineF(p, cpsStmts, "}$n") # else statement:
|
||||
lineF(p, cpsStmts, "}$n", []) # else statement:
|
||||
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
|
||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
|
||||
# third pass: generate statements
|
||||
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
|
||||
fixLabel(p, lend)
|
||||
@@ -718,13 +739,13 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
genCaseRange(p, branch)
|
||||
else:
|
||||
# else part of case statement:
|
||||
lineF(p, cpsStmts, "default:$n")
|
||||
lineF(p, cpsStmts, "default:$n", [])
|
||||
hasDefault = true
|
||||
exprBlock(p, branch.lastSon, d)
|
||||
lineF(p, cpsStmts, "break;$n")
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
if (hasAssume in CC[cCompiler].props) and not hasDefault:
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n")
|
||||
lineF(p, cpsStmts, "}$n")
|
||||
lineF(p, cpsStmts, "default: __assume(0);$n", [])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
if lend != nil: fixLabel(p, lend)
|
||||
|
||||
proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
@@ -738,7 +759,10 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
"if ($1 == $2) goto $3;$n")
|
||||
else:
|
||||
genOrdinalCase(p, t, d)
|
||||
if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
|
||||
genGotoForCase(p, t)
|
||||
else:
|
||||
genOrdinalCase(p, t, d)
|
||||
|
||||
proc hasGeneralExceptSection(t: PNode): bool =
|
||||
var length = sonsLen(t)
|
||||
@@ -774,7 +798,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
var
|
||||
exc: PRope
|
||||
exc: Rope
|
||||
i, length, blen: int
|
||||
genLineDir(p, t)
|
||||
exc = getTempName()
|
||||
@@ -794,16 +818,16 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var catchAllPresent = false
|
||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||
blen = sonsLen(t.sons[i])
|
||||
if i > 1: appf(p.s(cpsStmts), "else ")
|
||||
if i > 1: addf(p.s(cpsStmts), "else ", [])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
catchAllPresent = true
|
||||
exprBlock(p, t.sons[i].sons[0], d)
|
||||
else:
|
||||
var orExpr: PRope = nil
|
||||
var orExpr: Rope = nil
|
||||
for j in countup(0, blen - 2):
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: app(orExpr, "||")
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
appcg(p.module, orExpr,
|
||||
"#isObj($1.exp->m_type, $2)",
|
||||
[exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||
@@ -814,7 +838,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# reraise the exception if there was no catch all
|
||||
# and none of the handlers matched
|
||||
if not catchAllPresent:
|
||||
if i > 1: lineF(p, cpsStmts, "else ")
|
||||
if i > 1: lineF(p, cpsStmts, "else ", [])
|
||||
startBlock(p)
|
||||
var finallyBlock = t.lastSon
|
||||
if finallyBlock.kind == nkFinally:
|
||||
@@ -824,7 +848,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
endBlock(p)
|
||||
|
||||
lineF(p, cpsStmts, "}$n") # end of catch block
|
||||
lineF(p, cpsStmts, "}$n", []) # end of catch block
|
||||
dec p.inExceptBlock
|
||||
|
||||
discard pop(p.nestedTryStmts)
|
||||
@@ -895,17 +919,17 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
var blen = sonsLen(t.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
if i > 1: lineF(p, cpsStmts, "else")
|
||||
if i > 1: lineF(p, cpsStmts, "else", [])
|
||||
startBlock(p)
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
|
||||
expr(p, t.sons[i].sons[0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n")
|
||||
endBlock(p)
|
||||
else:
|
||||
var orExpr: PRope = nil
|
||||
var orExpr: Rope = nil
|
||||
for j in countup(0, blen - 2):
|
||||
assert(t.sons[i].sons[j].kind == nkType)
|
||||
if orExpr != nil: app(orExpr, "||")
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
appcg(p.module, orExpr,
|
||||
"#isObj(#getCurrentException()->Sup.m_type, $1)",
|
||||
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
|
||||
@@ -925,7 +949,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
discard pop(p.finallySafePoints)
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
|
||||
var res = ""
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
case t.sons[i].kind
|
||||
@@ -936,7 +960,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[i], a)
|
||||
res.add(rdLoc(a).ropeToStr)
|
||||
res.add($rdLoc(a))
|
||||
else:
|
||||
var r = sym.loc.r
|
||||
if r == nil:
|
||||
@@ -944,7 +968,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||
# it doesn't matter much:
|
||||
r = mangleName(sym)
|
||||
sym.loc.r = r # but be consequent!
|
||||
res.add(r.ropeToStr)
|
||||
res.add($r)
|
||||
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
|
||||
|
||||
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
|
||||
@@ -954,15 +978,15 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||
if x[j] in {'"', ':'}:
|
||||
# don't modify the line if already in quotes or
|
||||
# some clobber register list:
|
||||
app(result, x); app(result, tnl)
|
||||
add(result, x); add(result, tnl)
|
||||
elif x[j] != '\0':
|
||||
# ignore empty lines
|
||||
app(result, "\"")
|
||||
app(result, x)
|
||||
app(result, "\\n\"\n")
|
||||
add(result, "\"")
|
||||
add(result, x)
|
||||
add(result, "\\n\"\n")
|
||||
else:
|
||||
res.add(tnl)
|
||||
result = res.toRope
|
||||
result = res.rope
|
||||
|
||||
proc genAsmStmt(p: BProc, t: PNode) =
|
||||
assert(t.kind == nkAsmStmt)
|
||||
@@ -973,7 +997,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
||||
# work:
|
||||
if p.prc == nil:
|
||||
# top level asm statement?
|
||||
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
|
||||
addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
|
||||
else:
|
||||
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
|
||||
|
||||
@@ -982,14 +1006,14 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
if p.prc == nil:
|
||||
# top level emit pragma?
|
||||
genCLineDir(p.module.s[cfsProcHeaders], t.info)
|
||||
app(p.module.s[cfsProcHeaders], s)
|
||||
add(p.module.s[cfsProcHeaders], s)
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
line(p, cpsStmts, s)
|
||||
|
||||
var
|
||||
breakPointId: int = 0
|
||||
gBreakpoints: PRope # later the breakpoints are inserted into the main proc
|
||||
gBreakpoints: Rope # later the breakpoints are inserted into the main proc
|
||||
|
||||
proc genBreakPoint(p: BProc, t: PNode) =
|
||||
var name: string
|
||||
@@ -1003,7 +1027,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
|
||||
genLineDir(p, t) # BUGFIX
|
||||
appcg(p.module, gBreakpoints,
|
||||
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
|
||||
toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
|
||||
rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
|
||||
makeCString(name)])
|
||||
|
||||
proc genWatchpoint(p: BProc, n: PNode) =
|
||||
@@ -1066,7 +1090,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
|
||||
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
genLineDir(p, e)
|
||||
if not fieldDiscriminantCheckNeeded(p, e):
|
||||
if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
|
||||
genGotoVar(p, e.sons[1])
|
||||
elif not fieldDiscriminantCheckNeeded(p, e):
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Thread var support for crappy architectures that lack native support for
|
||||
## Thread var support for crappy architectures that lack native support for
|
||||
## thread local storage. (**Thank you Mac OS X!**)
|
||||
|
||||
# included from cgen.nim
|
||||
@@ -19,12 +19,12 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||
if emulatedThreadVars() and not p.threadVarAccessed:
|
||||
p.threadVarAccessed = true
|
||||
p.module.usesThreadVars = true
|
||||
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
|
||||
app(p.procSec(cpsInit),
|
||||
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
|
||||
add(p.procSec(cpsInit),
|
||||
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
|
||||
|
||||
|
||||
var
|
||||
nimtv: PRope # nimrod thread vars; the struct body
|
||||
nimtv: Rope # nimrod thread vars; the struct body
|
||||
nimtvDeps: seq[PType] = @[] # type deps: every module needs whole struct
|
||||
nimtvDeclared = initIntSet() # so that every var/field exists only once
|
||||
# in the struct
|
||||
@@ -43,23 +43,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
|
||||
# allocator for it :-(
|
||||
if not containsOrIncl(nimtvDeclared, s.id):
|
||||
nimtvDeps.add(s.loc.t)
|
||||
appf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
|
||||
addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
|
||||
else:
|
||||
if isExtern: app(m.s[cfsVars], "extern ")
|
||||
if optThreads in gGlobalOptions: app(m.s[cfsVars], "NIM_THREADVAR ")
|
||||
app(m.s[cfsVars], getTypeDesc(m, s.loc.t))
|
||||
appf(m.s[cfsVars], " $1;$n", [s.loc.r])
|
||||
|
||||
if isExtern: add(m.s[cfsVars], "extern ")
|
||||
if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
|
||||
add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
|
||||
addf(m.s[cfsVars], " $1;$n", [s.loc.r])
|
||||
|
||||
proc generateThreadLocalStorage(m: BModule) =
|
||||
if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
|
||||
for t in items(nimtvDeps): discard getTypeDesc(m, t)
|
||||
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
|
||||
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
|
||||
|
||||
proc generateThreadVarsSize(m: BModule) =
|
||||
if nimtv != nil:
|
||||
let externc = if gCmd != cmdCompileToCpp and
|
||||
sfCompileToCpp in m.module.flags: "extern \"C\""
|
||||
else: ""
|
||||
appf(m.s[cfsProcs],
|
||||
addf(m.s[cfsProcs],
|
||||
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
|
||||
[externc.toRope])
|
||||
[externc.rope])
|
||||
|
||||
@@ -17,11 +17,11 @@ type
|
||||
p: BProc
|
||||
visitorFrmt: string
|
||||
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
|
||||
proc genCaseRange(p: BProc, branch: PNode)
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
|
||||
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
@@ -31,31 +31,31 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
|
||||
var p = c.p
|
||||
let disc = n.sons[0].sym
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
|
||||
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
let branch = n.sons[i]
|
||||
assert branch.kind in {nkOfBranch, nkElse}
|
||||
if branch.kind == nkOfBranch:
|
||||
genCaseRange(c.p, branch)
|
||||
else:
|
||||
lineF(p, cpsStmts, "default:$n")
|
||||
lineF(p, cpsStmts, "default:$n", [])
|
||||
genTraverseProc(c, accessor, lastSon(branch))
|
||||
lineF(p, cpsStmts, "break;$n")
|
||||
lineF(p, cpsStmts, "} $n")
|
||||
lineF(p, cpsStmts, "break;$n", [])
|
||||
lineF(p, cpsStmts, "} $n", [])
|
||||
of nkSym:
|
||||
let field = n.sym
|
||||
if field.loc.t == nil:
|
||||
internalError(n.info, "genTraverseProc()")
|
||||
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
|
||||
genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
|
||||
else: internalError(n.info, "genTraverseProc()")
|
||||
|
||||
proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
|
||||
proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
|
||||
if not m.compileToCpp:
|
||||
result = ropef("$1.Sup", accessor)
|
||||
result = "$1.Sup" % [accessor]
|
||||
else:
|
||||
result = accessor
|
||||
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
if typ == nil: return
|
||||
var p = c.p
|
||||
case typ.kind
|
||||
@@ -66,9 +66,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(tyInt), i)
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
i.r, arraySize.toRope)
|
||||
i.r, arraySize.rope)
|
||||
genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
|
||||
lineF(p, cpsStmts, "}$n")
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
of tyObject:
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
|
||||
@@ -76,7 +76,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
|
||||
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
|
||||
of tyRef, tyString, tySequence:
|
||||
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
|
||||
of tyProc:
|
||||
@@ -85,67 +85,67 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
else:
|
||||
discard
|
||||
|
||||
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
var p = c.p
|
||||
assert typ.kind == tySequence
|
||||
assert typ.kind == tySequence
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(tyInt), i)
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
|
||||
i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
|
||||
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
|
||||
lineF(p, cpsStmts, "}$n")
|
||||
|
||||
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||
[i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
|
||||
genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
|
||||
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
|
||||
var c: TTraversalClosure
|
||||
var p = newProc(nil, m)
|
||||
result = getGlobalTempName()
|
||||
|
||||
|
||||
case reason
|
||||
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
|
||||
else: assert false
|
||||
|
||||
let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
|
||||
|
||||
|
||||
let header = "N_NIMCALL(void, $1)(void* p, NI op)" % [result]
|
||||
|
||||
let t = getTypeDesc(m, typ)
|
||||
lineF(p, cpsLocals, "$1 a;$n", t)
|
||||
lineF(p, cpsInit, "a = ($1)p;$n", t)
|
||||
|
||||
lineF(p, cpsLocals, "$1 a;$n", [t])
|
||||
lineF(p, cpsInit, "a = ($1)p;$n", [t])
|
||||
|
||||
c.p = p
|
||||
assert typ.kind != tyTypeDesc
|
||||
if typ.kind == tySequence:
|
||||
genTraverseProcSeq(c, "a".toRope, typ)
|
||||
genTraverseProcSeq(c, "a".rope, typ)
|
||||
else:
|
||||
if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
|
||||
# C's arrays are broken beyond repair:
|
||||
genTraverseProc(c, "a".toRope, typ.sons[0])
|
||||
genTraverseProc(c, "a".rope, typ.sons[0])
|
||||
else:
|
||||
genTraverseProc(c, "(*a)".toRope, typ.sons[0])
|
||||
|
||||
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
|
||||
m.s[cfsProcHeaders].appf("$1;$n", header)
|
||||
m.s[cfsProcs].app(generatedProc)
|
||||
genTraverseProc(c, "(*a)".rope, typ.sons[0])
|
||||
|
||||
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
|
||||
let generatedProc = "$1 {$n$2$3$4}$n" %
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addf("$1;$n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
|
||||
proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
|
||||
discard genTypeInfo(m, s.loc.t)
|
||||
|
||||
|
||||
var c: TTraversalClosure
|
||||
var p = newProc(nil, m)
|
||||
var sLoc = s.loc.r
|
||||
result = getGlobalTempName()
|
||||
|
||||
|
||||
if sfThread in s.flags and emulatedThreadVars():
|
||||
accessThreadLocalVar(p, s)
|
||||
sLoc = con("NimTV->", sLoc)
|
||||
|
||||
sLoc = "NimTV->" & sLoc
|
||||
|
||||
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
||||
c.p = p
|
||||
let header = ropef("N_NIMCALL(void, $1)()", result)
|
||||
let header = "N_NIMCALL(void, $1)()" % [result]
|
||||
genTraverseProc(c, sLoc, s.loc.t)
|
||||
|
||||
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
|
||||
m.s[cfsProcHeaders].appf("$1;$n", header)
|
||||
m.s[cfsProcs].app(generatedProc)
|
||||
|
||||
let generatedProc = "$1 {$n$2$3$4}$n" %
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addf("$1;$n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
|
||||
@@ -25,7 +25,7 @@ proc isKeyword(w: PIdent): bool =
|
||||
ord(wInline): return true
|
||||
else: return false
|
||||
|
||||
proc mangleName(s: PSym): PRope =
|
||||
proc mangleName(s: PSym): Rope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
when oKeepVariableNames:
|
||||
@@ -77,27 +77,27 @@ proc mangleName(s: PSym): PRope =
|
||||
# These are not properly scoped now - we need to add blocks
|
||||
# around for loops in transf
|
||||
if keepOrigName:
|
||||
result = s.name.s.mangle.newRope
|
||||
result = s.name.s.mangle.rope
|
||||
else:
|
||||
app(result, newRope(mangle(s.name.s)))
|
||||
app(result, ~"_")
|
||||
app(result, toRope(s.id))
|
||||
add(result, rope(mangle(s.name.s)))
|
||||
add(result, ~"_")
|
||||
add(result, rope(s.id))
|
||||
else:
|
||||
app(result, newRope(mangle(s.name.s)))
|
||||
app(result, ~"_")
|
||||
app(result, toRope(s.id))
|
||||
add(result, rope(mangle(s.name.s)))
|
||||
add(result, ~"_")
|
||||
add(result, rope(s.id))
|
||||
s.loc.r = result
|
||||
|
||||
proc typeName(typ: PType): PRope =
|
||||
result = if typ.sym != nil: typ.sym.name.s.mangle.toRope
|
||||
proc typeName(typ: PType): Rope =
|
||||
result = if typ.sym != nil: typ.sym.name.s.mangle.rope
|
||||
else: ~"TY"
|
||||
|
||||
proc getTypeName(typ: PType): PRope =
|
||||
proc getTypeName(typ: PType): Rope =
|
||||
if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
|
||||
result = typ.sym.loc.r
|
||||
else:
|
||||
if typ.loc.r == nil:
|
||||
typ.loc.r = con(typ.typeName, typ.id.toRope)
|
||||
typ.loc.r = typ.typeName & typ.id.rope
|
||||
result = typ.loc.r
|
||||
if result == nil: internalError("getTypeName: " & $typ.kind)
|
||||
|
||||
@@ -156,7 +156,7 @@ proc isImportedType(t: PType): bool =
|
||||
proc isImportedCppType(t: PType): bool =
|
||||
result = t.sym != nil and sfInfixCall in t.sym.flags
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope
|
||||
proc needsComplexAssignment(typ: PType): bool =
|
||||
result = containsGarbageCollectedRef(typ)
|
||||
|
||||
@@ -189,17 +189,17 @@ const
|
||||
# but one can #define it to what one wants
|
||||
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
|
||||
|
||||
proc cacheGetType(tab: TIdTable, key: PType): PRope =
|
||||
proc cacheGetType(tab: TIdTable, key: PType): Rope =
|
||||
# returns nil if we need to declare this type
|
||||
# since types are now unique via the ``getUniqueType`` mechanism, this slow
|
||||
# linear search is not necessary anymore:
|
||||
result = PRope(idTableGet(tab, key))
|
||||
result = Rope(idTableGet(tab, key))
|
||||
|
||||
proc getTempName(): PRope =
|
||||
result = rfmt(nil, "TMP$1", toRope(backendId()))
|
||||
proc getTempName(): Rope =
|
||||
result = rfmt(nil, "TMP$1", rope(backendId()))
|
||||
|
||||
proc getGlobalTempName(): PRope =
|
||||
result = rfmt(nil, "TMP$1", toRope(backendId()))
|
||||
proc getGlobalTempName(): Rope =
|
||||
result = rfmt(nil, "TMP$1", rope(backendId()))
|
||||
|
||||
proc ccgIntroducedPtr(s: PSym): bool =
|
||||
var pt = skipTypes(s.typ, typedescInst)
|
||||
@@ -226,13 +226,13 @@ proc fillResult(param: PSym) =
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
|
||||
proc typeNameOrLiteral(t: PType, literal: string): PRope =
|
||||
proc typeNameOrLiteral(t: PType, literal: string): Rope =
|
||||
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
|
||||
result = getTypeName(t)
|
||||
else:
|
||||
result = toRope(literal)
|
||||
result = rope(literal)
|
||||
|
||||
proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||
proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||
const
|
||||
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
|
||||
"NI", "NI8", "NI16", "NI32", "NI64",
|
||||
@@ -268,20 +268,20 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||
proc pushType(m: BModule, typ: PType) =
|
||||
add(m.typeStack, typ)
|
||||
|
||||
proc getTypePre(m: BModule, typ: PType): PRope =
|
||||
if typ == nil: result = toRope("void")
|
||||
proc getTypePre(m: BModule, typ: PType): Rope =
|
||||
if typ == nil: result = rope("void")
|
||||
else:
|
||||
result = getSimpleTypeDesc(m, typ)
|
||||
if result == nil: result = cacheGetType(m.typeCache, typ)
|
||||
|
||||
proc structOrUnion(t: PType): PRope =
|
||||
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||
proc structOrUnion(t: PType): Rope =
|
||||
(if tfUnion in t.flags: rope("union") else: rope("struct"))
|
||||
|
||||
proc getForwardStructFormat(m: BModule): string =
|
||||
if m.compileToCpp: result = "$1 $2;$n"
|
||||
else: result = "typedef $1 $2 $2;$n"
|
||||
|
||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
proc getTypeForward(m: BModule, typ: PType): Rope =
|
||||
result = cacheGetType(m.forwTypeCache, typ)
|
||||
if result != nil: return
|
||||
result = getTypePre(m, typ)
|
||||
@@ -290,12 +290,12 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
of tySequence, tyTuple, tyObject:
|
||||
result = getTypeName(typ)
|
||||
if not isImportedType(typ):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(typ), result])
|
||||
idTablePut(m.forwTypeCache, typ, result)
|
||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||
|
||||
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
|
||||
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||
## like getTypeDescAux but creates only a *weak* dependency. In other words
|
||||
## we know we only need a pointer to it so we only generate a struct forward
|
||||
## declaration:
|
||||
@@ -310,7 +310,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
|
||||
pushType(m, x)
|
||||
of tySequence:
|
||||
let x = getUniqueType(etB)
|
||||
result = getTypeForward(m, x).con("*")
|
||||
result = getTypeForward(m, x) & "*"
|
||||
pushType(m, x)
|
||||
else:
|
||||
result = getTypeDescAux(m, t, check)
|
||||
@@ -321,7 +321,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||
else:
|
||||
result = OnUnknown
|
||||
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
check: var IntSet, declareEnvironment=true) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
@@ -332,18 +332,18 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if params != nil: app(params, ~", ")
|
||||
if params != nil: add(params, ~", ")
|
||||
fillLoc(param.loc, locParam, param.typ, mangleName(param),
|
||||
param.paramStorageLoc)
|
||||
if ccgIntroducedPtr(param):
|
||||
app(params, getTypeDescWeak(m, param.typ, check))
|
||||
app(params, ~"*")
|
||||
add(params, getTypeDescWeak(m, param.typ, check))
|
||||
add(params, ~"*")
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
else:
|
||||
app(params, getTypeDescAux(m, param.typ, check))
|
||||
app(params, ~" ")
|
||||
app(params, param.loc.r)
|
||||
add(params, getTypeDescAux(m, param.typ, check))
|
||||
add(params, ~" ")
|
||||
add(params, param.loc.r)
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ
|
||||
if arr.kind == tyVar: arr = arr.sons[0]
|
||||
@@ -352,78 +352,78 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind == tyVar: param.loc.s = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
appf(params, ", NI $1Len$2", [param.loc.r, j.toRope])
|
||||
addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
|
||||
inc(j)
|
||||
arr = arr.sons[0]
|
||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||
var arr = t.sons[0]
|
||||
if params != nil: app(params, ", ")
|
||||
if params != nil: add(params, ", ")
|
||||
if (mapReturnType(t.sons[0]) != ctArray):
|
||||
app(params, getTypeDescWeak(m, arr, check))
|
||||
app(params, "*")
|
||||
add(params, getTypeDescWeak(m, arr, check))
|
||||
add(params, "*")
|
||||
else:
|
||||
app(params, getTypeDescAux(m, arr, check))
|
||||
appf(params, " Result", [])
|
||||
add(params, getTypeDescAux(m, arr, check))
|
||||
addf(params, " Result", [])
|
||||
if t.callConv == ccClosure and declareEnvironment:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "void* ClEnv")
|
||||
if params != nil: add(params, ", ")
|
||||
add(params, "void* ClEnv")
|
||||
if tfVarargs in t.flags:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "...")
|
||||
if params == nil: app(params, "void)")
|
||||
else: app(params, ")")
|
||||
params = con("(", params)
|
||||
if params != nil: add(params, ", ")
|
||||
add(params, "...")
|
||||
if params == nil: add(params, "void)")
|
||||
else: add(params, ")")
|
||||
params = "(" & params
|
||||
|
||||
proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
||||
proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
|
||||
if (rectype.sym != nil) and
|
||||
({sfImportc, sfExportc} * rectype.sym.flags != {}):
|
||||
result = field.loc.r
|
||||
else:
|
||||
result = toRope(mangleField(field.name.s))
|
||||
result = rope(mangleField(field.name.s))
|
||||
if result == nil: internalError(field.info, "mangleRecFieldName")
|
||||
|
||||
proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
accessExpr: PRope, rectype: PType,
|
||||
check: var IntSet): PRope =
|
||||
accessExpr: Rope, rectype: PType,
|
||||
check: var IntSet): Rope =
|
||||
var
|
||||
ae, uname, sname, a: PRope
|
||||
ae, uname, sname, a: Rope
|
||||
k: PNode
|
||||
field: PSym
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
|
||||
add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
|
||||
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
|
||||
uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
|
||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
|
||||
add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
|
||||
uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
|
||||
if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname]
|
||||
else: ae = uname
|
||||
var unionBody: PRope = nil
|
||||
var unionBody: Rope = nil
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
k = lastSon(n.sons[i])
|
||||
if k.kind != nkSym:
|
||||
sname = con("S", toRope(i))
|
||||
a = genRecordFieldsAux(m, k, ropef("$1.$2", [ae, sname]), rectype,
|
||||
sname = "S" & rope(i)
|
||||
a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
|
||||
check)
|
||||
if a != nil:
|
||||
app(unionBody, "struct {")
|
||||
app(unionBody, a)
|
||||
appf(unionBody, "} $1;$n", [sname])
|
||||
add(unionBody, "struct {")
|
||||
add(unionBody, a)
|
||||
addf(unionBody, "} $1;$n", [sname])
|
||||
else:
|
||||
app(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
|
||||
add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
|
||||
else: internalError("genRecordFieldsAux(record case branch)")
|
||||
if unionBody != nil:
|
||||
appf(result, "union{$n$1} $2;$n", [unionBody, uname])
|
||||
addf(result, "union{$n$1} $2;$n", [unionBody, uname])
|
||||
of nkSym:
|
||||
field = n.sym
|
||||
if field.typ.kind == tyEmpty: return
|
||||
#assert(field.ast == nil)
|
||||
sname = mangleRecFieldName(field, rectype)
|
||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||
if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
|
||||
else: ae = sname
|
||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||
# for importcpp'ed objects, we only need to set field.loc, but don't
|
||||
@@ -432,27 +432,27 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
if not isImportedCppType(rectype):
|
||||
let fieldType = field.loc.t.skipTypes(abstractInst)
|
||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||
elif fieldType.kind == tySequence:
|
||||
# we need to use a weak dependency here for trecursive_table.
|
||||
appf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||
addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||
else: internalError(n.info, "genRecordFieldsAux()")
|
||||
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
|
||||
|
||||
proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var IntSet): PRope =
|
||||
proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
check: var IntSet): Rope =
|
||||
# declare the record:
|
||||
var hasField = false
|
||||
|
||||
var attribute: PRope =
|
||||
if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
|
||||
var attribute: Rope =
|
||||
if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
|
||||
else: nil
|
||||
|
||||
result = ropecg(m, CC[cCompiler].structStmtFmt,
|
||||
@@ -475,27 +475,54 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
else:
|
||||
appf(result, " {$n", [name])
|
||||
addf(result, " {$n", [name])
|
||||
|
||||
var desc = getRecordFields(m, typ, check)
|
||||
if desc == nil and not hasField:
|
||||
appf(result, "char dummy;$n", [])
|
||||
addf(result, "char dummy;$n", [])
|
||||
else:
|
||||
app(result, desc)
|
||||
app(result, "};" & tnl)
|
||||
add(result, desc)
|
||||
add(result, "};" & tnl)
|
||||
|
||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var IntSet): PRope =
|
||||
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||
var desc: PRope = nil
|
||||
proc getTupleDesc(m: BModule, typ: PType, name: Rope,
|
||||
check: var IntSet): Rope =
|
||||
result = "$1 $2 {$n" % [structOrUnion(typ), name]
|
||||
var desc: Rope = nil
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
appf(desc, "$1 Field$2;$n",
|
||||
[getTypeDescAux(m, typ.sons[i], check), toRope(i)])
|
||||
if desc == nil: app(result, "char dummy;" & tnl)
|
||||
else: app(result, desc)
|
||||
app(result, "};" & tnl)
|
||||
addf(desc, "$1 Field$2;$n",
|
||||
[getTypeDescAux(m, typ.sons[i], check), rope(i)])
|
||||
if desc == nil: add(result, "char dummy;" & tnl)
|
||||
else: add(result, desc)
|
||||
add(result, "};" & tnl)
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
|
||||
# A helper proc for handling cppimport patterns, involving numeric
|
||||
# placeholders for generic types (e.g. '0, '**2, etc).
|
||||
# pre: the cursor must be placed at the ' symbol
|
||||
# post: the cursor will be placed after the final digit
|
||||
# false will returned if the input is not recognized as a placeholder
|
||||
inc cursor
|
||||
let begin = cursor
|
||||
while pat[cursor] == '*': inc cursor
|
||||
if pat[cursor] in Digits:
|
||||
outIdx = pat[cursor].ord - '0'.ord
|
||||
outStars = cursor - begin
|
||||
inc cursor
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||
# XXX: we should catch this earlier and report it as a semantic error
|
||||
if idx >= typ.len: internalError "invalid apostrophe type parameter index"
|
||||
|
||||
result = typ.sons[idx]
|
||||
for i in 1..stars:
|
||||
if result != nil and result.len > 0:
|
||||
result = if result.kind == tyGenericInst: result.sons[1]
|
||||
else: result.elemType
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
# returns only the type's name
|
||||
var t = getUniqueType(typ)
|
||||
if t == nil: internalError("getTypeDescAux: t == nil")
|
||||
@@ -523,39 +550,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
case etB.kind
|
||||
of tyObject, tyTuple:
|
||||
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
||||
result = con(getTypeDescAux(m, et, check), star)
|
||||
result = getTypeDescAux(m, et, check) & star
|
||||
else:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let x = getUniqueType(etB)
|
||||
let name = getTypeForward(m, x)
|
||||
result = con(name, star)
|
||||
result = name & star
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, x)
|
||||
of tySequence:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let x = getUniqueType(etB)
|
||||
let name = getTypeForward(m, x)
|
||||
result = con(name, "*" & star)
|
||||
result = name & "*" & star
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, x)
|
||||
else:
|
||||
# else we have a strong dependency :-(
|
||||
result = con(getTypeDescAux(m, et, check), star)
|
||||
result = getTypeDescAux(m, et, check) & star
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = con(getTypeDescAux(m, t.sons[0], check), "*")
|
||||
result = getTypeDescAux(m, t.sons[0], check) & "*"
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyProc:
|
||||
result = getTypeName(t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
var rettype, desc: PRope
|
||||
var rettype, desc: Rope
|
||||
genProcParams(m, t, rettype, desc, check)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure: # procedure vars may need a closure!
|
||||
appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
|
||||
[toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
|
||||
addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
|
||||
[rope(CallingConvToStr[t.callConv]), rettype, result, desc])
|
||||
else:
|
||||
appf(m.s[cfsTypes], "typedef struct {$n" &
|
||||
addf(m.s[cfsTypes], "typedef struct {$n" &
|
||||
"N_NIMCALL_PTR($2, ClPrc) $3;$n" &
|
||||
"void* ClEnv;$n} $1;$n",
|
||||
[result, rettype, desc])
|
||||
@@ -566,11 +593,11 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
assert(cacheGetType(m.typeCache, t) == nil)
|
||||
idTablePut(m.typeCache, t, con(result, "*"))
|
||||
idTablePut(m.typeCache, t, result & "*")
|
||||
if not isImportedType(t):
|
||||
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
|
||||
const
|
||||
@@ -582,8 +609,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
" $1 data[SEQ_DECL_SIZE];$n" &
|
||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||
else:
|
||||
result = toRope("TGenericSeq")
|
||||
app(result, "*")
|
||||
result = rope("TGenericSeq")
|
||||
add(result, "*")
|
||||
of tyArrayConstr, tyArray:
|
||||
var n: BiggestInt = lengthOrd(t)
|
||||
if n <= 0: n = 1 # make an array of at least one element
|
||||
@@ -591,17 +618,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
let foo = getTypeDescAux(m, t.sons[1], check)
|
||||
appf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
|
||||
[foo, result, toRope(n)])
|
||||
addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
|
||||
[foo, result, rope(n)])
|
||||
of tyObject, tyTuple:
|
||||
if isImportedCppType(t) and typ.kind == tyGenericInst:
|
||||
# for instantiated templates we do not go through the type cache as the
|
||||
# the type cache is not aware of 'tyGenericInst'.
|
||||
result = getTypeName(t).con("<")
|
||||
for i in 1 .. typ.len-2:
|
||||
if i > 1: result.app(", ")
|
||||
result.app(getTypeDescAux(m, typ.sons[i], check))
|
||||
result.app("> ")
|
||||
let cppName = getTypeName(t)
|
||||
var i = 0
|
||||
var chunkStart = 0
|
||||
while i < cppName.data.len:
|
||||
if cppName.data[i] == '\'':
|
||||
var chunkEnd = <i
|
||||
var idx, stars: int
|
||||
if scanCppGenericSlot(cppName.data, i, idx, stars):
|
||||
result.add cppName.data.substr(chunkStart, chunkEnd)
|
||||
chunkStart = i
|
||||
|
||||
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
|
||||
if typeInSlot == nil or typeInSlot.kind == tyEmpty:
|
||||
result.add(~"void")
|
||||
else:
|
||||
result.add getTypeDescAux(m, typeInSlot, check)
|
||||
else:
|
||||
inc i
|
||||
|
||||
if chunkStart != 0:
|
||||
result.add cppName.data.substr(chunkStart)
|
||||
else:
|
||||
result = cppName & "<"
|
||||
for i in 1 .. typ.len-2:
|
||||
if i > 1: result.add(", ")
|
||||
result.add(getTypeDescAux(m, typ.sons[i], check))
|
||||
result.add("> ")
|
||||
# always call for sideeffects:
|
||||
assert t.kind != tyTuple
|
||||
discard getRecordDesc(m, t, result, check)
|
||||
@@ -610,25 +659,25 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result) # always call for sideeffects:
|
||||
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
|
||||
else: getTupleDesc(m, t, result, check)
|
||||
if not isImportedType(t): app(m.s[cfsTypes], recdesc)
|
||||
if not isImportedType(t): add(m.s[cfsTypes], recdesc)
|
||||
of tySet:
|
||||
case int(getSize(t))
|
||||
of 1: result = toRope("NU8")
|
||||
of 2: result = toRope("NU16")
|
||||
of 4: result = toRope("NU32")
|
||||
of 8: result = toRope("NU64")
|
||||
of 1: result = rope("NU8")
|
||||
of 2: result = rope("NU16")
|
||||
of 4: result = rope("NU32")
|
||||
of 8: result = rope("NU64")
|
||||
else:
|
||||
result = getTypeName(t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
[result, toRope(getSize(t))])
|
||||
addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
[result, rope(getSize(t))])
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
|
||||
tyIter, tyTypeDesc:
|
||||
result = getTypeDescAux(m, lastSon(t), check)
|
||||
@@ -638,7 +687,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
# fixes bug #145:
|
||||
excl(check, t.id)
|
||||
|
||||
proc getTypeDesc(m: BModule, typ: PType): PRope =
|
||||
proc getTypeDesc(m: BModule, typ: PType): Rope =
|
||||
var check = initIntSet()
|
||||
result = getTypeDescAux(m, typ, check)
|
||||
|
||||
@@ -646,23 +695,23 @@ type
|
||||
TClosureTypeKind = enum
|
||||
clHalf, clHalfWithEnv, clFull
|
||||
|
||||
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): PRope =
|
||||
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
|
||||
assert t.kind == tyProc
|
||||
var check = initIntSet()
|
||||
result = getTempName()
|
||||
var rettype, desc: PRope
|
||||
var rettype, desc: Rope
|
||||
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure or kind != clFull:
|
||||
appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
|
||||
[toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
|
||||
addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
|
||||
[rope(CallingConvToStr[t.callConv]), rettype, result, desc])
|
||||
else:
|
||||
appf(m.s[cfsTypes], "typedef struct {$n" &
|
||||
addf(m.s[cfsTypes], "typedef struct {$n" &
|
||||
"N_NIMCALL_PTR($2, ClPrc) $3;$n" &
|
||||
"void* ClEnv;$n} $1;$n",
|
||||
[result, rettype, desc])
|
||||
|
||||
proc getTypeDesc(m: BModule, magic: string): PRope =
|
||||
proc getTypeDesc(m: BModule, magic: string): Rope =
|
||||
var sym = magicsys.getCompilerProc(magic)
|
||||
if sym != nil:
|
||||
result = getTypeDesc(m, sym.typ)
|
||||
@@ -678,38 +727,38 @@ proc finishTypeDescriptions(m: BModule) =
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
|
||||
|
||||
proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
proc genProcHeader(m: BModule, prc: PSym): Rope =
|
||||
var
|
||||
rettype, params: PRope
|
||||
rettype, params: Rope
|
||||
genCLineDir(result, prc.info)
|
||||
# using static is needed for inline procs
|
||||
if lfExportLib in prc.loc.flags:
|
||||
if m.isHeaderFile:
|
||||
result.app "N_LIB_IMPORT "
|
||||
result.add "N_LIB_IMPORT "
|
||||
else:
|
||||
result.app "N_LIB_EXPORT "
|
||||
result.add "N_LIB_EXPORT "
|
||||
elif prc.typ.callConv == ccInline:
|
||||
result.app "static "
|
||||
result.add "static "
|
||||
var check = initIntSet()
|
||||
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
# careful here! don't access ``prc.ast`` as that could reload large parts of
|
||||
# the object graph!
|
||||
if prc.constraint.isNil:
|
||||
appf(result, "$1($2, $3)$4",
|
||||
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
|
||||
addf(result, "$1($2, $3)$4",
|
||||
[rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
|
||||
params])
|
||||
else:
|
||||
result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
|
||||
result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
|
||||
|
||||
# ------------------ type info generation -------------------------------------
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope
|
||||
proc getNimNode(m: BModule): PRope =
|
||||
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
|
||||
proc genTypeInfo(m: BModule, t: PType): Rope
|
||||
proc getNimNode(m: BModule): Rope =
|
||||
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
|
||||
inc(m.typeNodes)
|
||||
|
||||
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
|
||||
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
|
||||
var nimtypeKind: int
|
||||
#allocMemTI(m, typ, name)
|
||||
if isObjLackingTypeField(typ):
|
||||
@@ -717,48 +766,47 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
|
||||
else:
|
||||
nimtypeKind = ord(typ.kind)
|
||||
|
||||
var size: PRope
|
||||
if tfIncompleteStruct in typ.flags: size = toRope"void*"
|
||||
var size: Rope
|
||||
if tfIncompleteStruct in typ.flags: size = rope"void*"
|
||||
elif m.compileToCpp: size = getTypeDesc(m, origType)
|
||||
else: size = getTypeDesc(m, typ)
|
||||
appf(m.s[cfsTypeInit3],
|
||||
addf(m.s[cfsTypeInit3],
|
||||
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
|
||||
[name, size, toRope(nimtypeKind), base])
|
||||
[name, size, rope(nimtypeKind), base])
|
||||
# compute type flags for GC optimization
|
||||
var flags = 0
|
||||
if not containsGarbageCollectedRef(typ): flags = flags or 1
|
||||
if not canFormAcycle(typ): flags = flags or 2
|
||||
#else MessageOut("can contain a cycle: " & typeToString(typ))
|
||||
if flags != 0:
|
||||
appf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, toRope(flags)])
|
||||
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
|
||||
discard cgsym(m, "TNimType")
|
||||
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
|
||||
[name, toRope(typeToString(typ))])
|
||||
addf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
|
||||
[name, rope(typeToString(typ))])
|
||||
|
||||
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
|
||||
var base: PRope
|
||||
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
|
||||
var base: Rope
|
||||
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
|
||||
base = genTypeInfo(m, typ.sons[0])
|
||||
else:
|
||||
base = toRope("0")
|
||||
base = rope("0")
|
||||
genTypeInfoAuxBase(m, typ, origType, name, base)
|
||||
|
||||
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
|
||||
# bugfix: we need to search the type that contains the discriminator:
|
||||
var objtype = objtype
|
||||
while lookupInRecord(objtype.n, d.name) == nil:
|
||||
objtype = objtype.sons[0]
|
||||
if objtype.sym == nil:
|
||||
internalError(d.info, "anonymous obj with discriminator")
|
||||
result = ropef("NimDT_$1_$2", [
|
||||
toRope(objtype.id), toRope(d.name.s.mangle)])
|
||||
result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)]
|
||||
|
||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
|
||||
discard cgsym(m, "TNimNode")
|
||||
var tmp = discriminatorTableName(m, objtype, d)
|
||||
result = ropef("TNimNode* $1[$2];$n", [tmp, toRope(lengthOrd(d.typ)+1)])
|
||||
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
|
||||
|
||||
proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
|
||||
proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
var L = sonsLen(n)
|
||||
@@ -766,29 +814,29 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
|
||||
genObjectFields(m, typ, n.sons[0], expr)
|
||||
elif L > 0:
|
||||
var tmp = getTempName()
|
||||
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(L)])
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
|
||||
for i in countup(0, L-1):
|
||||
var tmp2 = getNimNode(m)
|
||||
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
|
||||
genObjectFields(m, typ, n.sons[i], tmp2)
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
|
||||
[expr, toRope(L), tmp])
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
|
||||
[expr, rope(L), tmp])
|
||||
else:
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, toRope(L)])
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
|
||||
of nkRecCase:
|
||||
assert(n.sons[0].kind == nkSym)
|
||||
var field = n.sons[0].sym
|
||||
var tmp = discriminatorTableName(m, typ, field)
|
||||
var L = lengthOrd(field.typ)
|
||||
assert L > 0
|
||||
appf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
|
||||
addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
|
||||
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
|
||||
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
|
||||
"$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
|
||||
genTypeInfo(m, field.typ),
|
||||
makeCString(field.name.s),
|
||||
tmp, toRope(L)])
|
||||
appf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, toRope(L+1)])
|
||||
tmp, rope(L)])
|
||||
addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
var b = n.sons[i] # branch
|
||||
var tmp2 = getNimNode(m)
|
||||
@@ -802,60 +850,60 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
|
||||
var x = int(getOrdValue(b.sons[j].sons[0]))
|
||||
var y = int(getOrdValue(b.sons[j].sons[1]))
|
||||
while x <= y:
|
||||
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(x), tmp2])
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
|
||||
inc(x)
|
||||
else:
|
||||
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
|
||||
[tmp, toRope(getOrdValue(b.sons[j])), tmp2])
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
|
||||
[tmp, rope(getOrdValue(b.sons[j])), tmp2])
|
||||
of nkElse:
|
||||
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
|
||||
[tmp, toRope(L), tmp2])
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
|
||||
[tmp, rope(L), tmp2])
|
||||
else: internalError(n.info, "genObjectFields(nkRecCase)")
|
||||
of nkSym:
|
||||
var field = n.sym
|
||||
appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
|
||||
addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
|
||||
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
|
||||
"$1.name = $5;$n", [expr, getTypeDesc(m, typ),
|
||||
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
|
||||
else: internalError(n.info, "genObjectFields")
|
||||
|
||||
proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
|
||||
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
|
||||
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
|
||||
else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
|
||||
else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
|
||||
var tmp = getNimNode(m)
|
||||
if not isImportedCppType(typ):
|
||||
genObjectFields(m, typ, typ.n, tmp)
|
||||
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||
var t = typ.sons[0]
|
||||
while t != nil:
|
||||
t = t.skipTypes(abstractInst)
|
||||
t.flags.incl tfObjHasKids
|
||||
t = t.sons[0]
|
||||
|
||||
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
|
||||
genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
|
||||
proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
|
||||
genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
|
||||
var expr = getNimNode(m)
|
||||
var length = sonsLen(typ)
|
||||
if length > 0:
|
||||
var tmp = getTempName()
|
||||
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(length)])
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
|
||||
for i in countup(0, length - 1):
|
||||
var a = typ.sons[i]
|
||||
var tmp2 = getNimNode(m)
|
||||
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
|
||||
appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
|
||||
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
|
||||
addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
|
||||
"$1.offset = offsetof($2, Field$3);$n" &
|
||||
"$1.typ = $4;$n" &
|
||||
"$1.name = \"Field$3\";$n",
|
||||
[tmp2, getTypeDesc(m, typ), toRope(i), genTypeInfo(m, a)])
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
|
||||
[expr, toRope(length), tmp])
|
||||
[tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)])
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
|
||||
[expr, rope(length), tmp])
|
||||
else:
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
|
||||
[expr, toRope(length)])
|
||||
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
|
||||
[expr, rope(length)])
|
||||
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
|
||||
|
||||
proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||
proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
|
||||
# Type information for enumerations is quite heavy, so we do some
|
||||
# optimizations here: The ``typ`` field is never set, as it is redundant
|
||||
# anyway. We generate a cstring array and a loop over it. Exceptional
|
||||
@@ -863,9 +911,9 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||
genTypeInfoAux(m, typ, typ, name)
|
||||
var nodePtrs = getTempName()
|
||||
var length = sonsLen(typ.n)
|
||||
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
||||
[nodePtrs, toRope(length)])
|
||||
var enumNames, specialCases: PRope
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
||||
[nodePtrs, rope(length)])
|
||||
var enumNames, specialCases: Rope
|
||||
var firstNimNode = m.typeNodes
|
||||
var hasHoles = false
|
||||
for i in countup(0, length - 1):
|
||||
@@ -874,38 +922,38 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||
var elemNode = getNimNode(m)
|
||||
if field.ast == nil:
|
||||
# no explicit string literal for the enum field, so use field.name:
|
||||
app(enumNames, makeCString(field.name.s))
|
||||
add(enumNames, makeCString(field.name.s))
|
||||
else:
|
||||
app(enumNames, makeCString(field.ast.strVal))
|
||||
if i < length - 1: app(enumNames, ", " & tnl)
|
||||
add(enumNames, makeCString(field.ast.strVal))
|
||||
if i < length - 1: add(enumNames, ", " & tnl)
|
||||
if field.position != i or tfEnumHasHoles in typ.flags:
|
||||
appf(specialCases, "$1.offset = $2;$n", [elemNode, toRope(field.position)])
|
||||
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
|
||||
hasHoles = true
|
||||
var enumArray = getTempName()
|
||||
var counter = getTempName()
|
||||
appf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
|
||||
appf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
|
||||
[enumArray, toRope(length), enumNames])
|
||||
appf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
|
||||
addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
|
||||
addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
|
||||
[enumArray, rope(length), enumNames])
|
||||
addf(m.s[cfsTypeInit3], "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,
|
||||
toRope(length), m.typeNodesName, toRope(firstNimNode), enumArray, nodePtrs])
|
||||
app(m.s[cfsTypeInit3], specialCases)
|
||||
appf(m.s[cfsTypeInit3],
|
||||
rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
|
||||
add(m.s[cfsTypeInit3], specialCases)
|
||||
addf(m.s[cfsTypeInit3],
|
||||
"$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
|
||||
[getNimNode(m), toRope(length), nodePtrs, name])
|
||||
[getNimNode(m), rope(length), nodePtrs, name])
|
||||
if hasHoles:
|
||||
# 1 << 2 is {ntfEnumHole}
|
||||
appf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
|
||||
addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
|
||||
|
||||
proc genSetInfo(m: BModule, typ: PType, name: PRope) =
|
||||
proc genSetInfo(m: BModule, typ: PType, name: Rope) =
|
||||
assert(typ.sons[0] != nil)
|
||||
genTypeInfoAux(m, typ, typ, name)
|
||||
var tmp = getNimNode(m)
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
||||
[tmp, toRope(firstOrd(typ)), name])
|
||||
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
||||
[tmp, rope(firstOrd(typ)), name])
|
||||
|
||||
proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
|
||||
proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
|
||||
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
|
||||
|
||||
proc fakeClosureType(owner: PSym): PType =
|
||||
@@ -925,17 +973,17 @@ type
|
||||
|
||||
include ccgtrav
|
||||
|
||||
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||
proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||
genProc(m, s)
|
||||
appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
||||
addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
||||
[result, s.loc.r])
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||
let origType = t
|
||||
var t = getUniqueType(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
result = "NTI$1" % [rope(t.id)]
|
||||
if containsOrIncl(m.typeInfoMarker, t.id):
|
||||
return con("(&".toRope, result, ")".toRope)
|
||||
return "(&".rope & result & ")".rope
|
||||
|
||||
# getUniqueType doesn't skip tyDistinct when that has an overriden operation:
|
||||
while t.kind == tyDistinct: t = t.lastSon
|
||||
@@ -946,23 +994,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
# reference the type info as extern here
|
||||
discard cgsym(m, "TNimType")
|
||||
discard cgsym(m, "TNimNode")
|
||||
appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
|
||||
[result, toRope(typeToString(t))])
|
||||
return con("(&".toRope, result, ")".toRope)
|
||||
addf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
|
||||
[result, rope(typeToString(t))])
|
||||
return "(&".rope & result & ")".rope
|
||||
case t.kind
|
||||
of tyEmpty: result = toRope"0"
|
||||
of tyEmpty: result = rope"0"
|
||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
else:
|
||||
genTupleInfo(m, fakeClosureType(t.owner), result)
|
||||
of tySequence, tyRef:
|
||||
genTypeInfoAux(m, t, t, result)
|
||||
if gSelectedGC >= gcMarkAndSweep:
|
||||
let markerProc = genTraverseProc(m, t, tiNew)
|
||||
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
||||
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
||||
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
|
||||
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
|
||||
of tySet: genSetInfo(m, t, result)
|
||||
@@ -979,7 +1027,7 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
genDeepCopyProc(m, t.deepCopy, result)
|
||||
elif origType.deepCopy != nil:
|
||||
genDeepCopyProc(m, origType.deepCopy, result)
|
||||
result = con("(&".toRope, result, ")".toRope)
|
||||
result = "(&".rope & result & ")".rope
|
||||
|
||||
proc genTypeSection(m: BModule, n: PNode) =
|
||||
discard
|
||||
|
||||
@@ -193,13 +193,13 @@ proc mangle*(name: string): string =
|
||||
else:
|
||||
add(result, "HEX" & toHex(ord(c), 2))
|
||||
|
||||
proc makeLLVMString*(s: string): PRope =
|
||||
proc makeLLVMString*(s: string): Rope =
|
||||
const MaxLineLength = 64
|
||||
result = nil
|
||||
var res = "c\""
|
||||
for i in countup(0, len(s) - 1):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
app(result, toRope(res))
|
||||
add(result, rope(res))
|
||||
setLen(res, 0)
|
||||
case s[i]
|
||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
||||
@@ -207,6 +207,6 @@ proc makeLLVMString*(s: string): PRope =
|
||||
add(res, toHex(ord(s[i]), 2))
|
||||
else: add(res, s[i])
|
||||
add(res, "\\00\"")
|
||||
app(result, toRope(res))
|
||||
add(result, rope(res))
|
||||
|
||||
initTypeTables()
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
## This module implements the C code generator.
|
||||
|
||||
import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp,
|
||||
options, intsets,
|
||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||
ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
|
||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
||||
semparallel
|
||||
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
when options.hasTinyCBackend:
|
||||
import tccgen
|
||||
|
||||
@@ -48,7 +50,7 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
||||
result.r = nil
|
||||
result.flags = {}
|
||||
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
|
||||
# fills the loc if it is not already initialized
|
||||
if a.k == locNone:
|
||||
a.k = k
|
||||
@@ -72,9 +74,9 @@ proc useHeader(m: BModule, sym: PSym) =
|
||||
assert(sym.annex != nil)
|
||||
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
|
||||
|
||||
proc cgsym(m: BModule, name: string): PRope
|
||||
proc cgsym(m: BModule, name: string): Rope
|
||||
|
||||
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
var i = 0
|
||||
var length = len(frmt)
|
||||
result = nil
|
||||
@@ -84,11 +86,11 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '$':
|
||||
app(result, "$")
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '#':
|
||||
inc(i)
|
||||
app(result, args[num])
|
||||
add(result, args[num])
|
||||
inc(num)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
@@ -99,12 +101,12 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
internalError("ropes: invalid format string $" & $j)
|
||||
app(result, args[j-1])
|
||||
add(result, args[j-1])
|
||||
of 'n':
|
||||
if optLineDir notin gOptions: app(result, rnl)
|
||||
if optLineDir notin gOptions: add(result, rnl)
|
||||
inc(i)
|
||||
of 'N':
|
||||
app(result, rnl)
|
||||
add(result, rnl)
|
||||
inc(i)
|
||||
else: internalError("ropes: invalid format string $" & frmt[i])
|
||||
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
|
||||
@@ -113,74 +115,74 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
while frmt[j] in IdentChars: inc(j)
|
||||
var ident = substr(frmt, i, j-1)
|
||||
i = j
|
||||
app(result, cgsym(m, ident))
|
||||
add(result, cgsym(m, ident))
|
||||
elif frmt[i] == '#' and frmt[i+1] == '$':
|
||||
inc(i, 2)
|
||||
var j = 0
|
||||
while frmt[i] in Digits:
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
app(result, cgsym(m, args[j-1].ropeToStr))
|
||||
add(result, cgsym(m, $args[j-1]))
|
||||
var start = i
|
||||
while i < length:
|
||||
if frmt[i] != '$' and frmt[i] != '#': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
app(result, substr(frmt, start, i - 1))
|
||||
add(result, substr(frmt, start, i - 1))
|
||||
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
|
||||
ropecg(m, fmt, args)
|
||||
|
||||
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(c, ropecg(m, frmt, args))
|
||||
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(c, ropecg(m, frmt, args))
|
||||
|
||||
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(m.s[s], ropecg(m, frmt, args))
|
||||
proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(m.s[s], ropecg(m, frmt, args))
|
||||
|
||||
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), ropecg(p.module, frmt, args))
|
||||
proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(p.s(s), ropecg(p.module, frmt, args))
|
||||
|
||||
var indent = "\t".toRope
|
||||
proc indentLine(p: BProc, r: PRope): PRope =
|
||||
var indent = "\t".rope
|
||||
proc indentLine(p: BProc, r: Rope): Rope =
|
||||
result = r
|
||||
for i in countup(0, p.blocks.len-1): prepend(result, indent)
|
||||
|
||||
proc line(p: BProc, s: TCProcSection, r: PRope) =
|
||||
app(p.s(s), indentLine(p, r))
|
||||
proc line(p: BProc, s: TCProcSection, r: Rope) =
|
||||
add(p.s(s), indentLine(p, r))
|
||||
|
||||
proc line(p: BProc, s: TCProcSection, r: string) =
|
||||
app(p.s(s), indentLine(p, r.toRope))
|
||||
add(p.s(s), indentLine(p, r.rope))
|
||||
|
||||
proc lineF(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropef(frmt, args)))
|
||||
proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||
args: openarray[Rope]) =
|
||||
add(p.s(s), indentLine(p, frmt % args))
|
||||
|
||||
proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(r, indentLine(p, ropecg(p.module, frmt, args)))
|
||||
proc appLineCg(p: BProc, r: var Rope, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
add(r, indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
proc safeLineNm(info: TLineInfo): int =
|
||||
result = toLinenumber(info)
|
||||
if result < 0: result = 0 # negative numbers are not allowed in #line
|
||||
|
||||
proc genCLineDir(r: var PRope, filename: string, line: int) =
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int) =
|
||||
assert line >= 0
|
||||
if optLineDir in gOptions:
|
||||
appf(r, "$N#line $2 $1$N",
|
||||
[toRope(makeSingleLineCString(filename)), toRope(line)])
|
||||
addf(r, "$N#line $2 $1$N",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var PRope, info: TLineInfo) =
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo) =
|
||||
genCLineDir(r, info.toFullPath, info.safeLineNm)
|
||||
|
||||
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
@@ -193,22 +195,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
var line = t.info.safeLineNm
|
||||
if optEmbedOrigSrc in gGlobalOptions:
|
||||
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
|
||||
add(p.s(cpsStmts), ~"//" & t.info.sourceLine & rnl)
|
||||
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
|
||||
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
if freshLineInfo(p, t.info):
|
||||
linefmt(p, cpsStmts, "#endb($1, $2);$n",
|
||||
line.toRope, makeCString(toFilename(t.info)))
|
||||
line.rope, makeCString(toFilename(t.info)))
|
||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||
{optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
|
||||
if freshLineInfo(p, t.info):
|
||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||
line.toRope, t.info.quotedFilename)
|
||||
line.rope, t.info.quotedFilename)
|
||||
|
||||
proc postStmtActions(p: BProc) {.inline.} =
|
||||
app(p.s(cpsStmts), p.module.injectStmt)
|
||||
add(p.s(cpsStmts), p.module.injectStmt)
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
@@ -221,21 +223,21 @@ include "ccgtypes.nim"
|
||||
|
||||
# ------------------------------ Manager of temporaries ------------------
|
||||
|
||||
proc rdLoc(a: TLoc): PRope =
|
||||
proc rdLoc(a: TLoc): Rope =
|
||||
# 'read' location (deref if indirect)
|
||||
result = a.r
|
||||
if lfIndirect in a.flags: result = ropef("(*$1)", [result])
|
||||
if lfIndirect in a.flags: result = "(*$1)" % [result]
|
||||
|
||||
proc addrLoc(a: TLoc): PRope =
|
||||
proc addrLoc(a: TLoc): Rope =
|
||||
result = a.r
|
||||
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
|
||||
result = con("(&", result).con(")")
|
||||
result = "(&" & result & ")"
|
||||
|
||||
proc rdCharLoc(a: TLoc): PRope =
|
||||
proc rdCharLoc(a: TLoc): Rope =
|
||||
# read a location that may need a char-cast:
|
||||
result = rdLoc(a)
|
||||
if skipTypes(a.t, abstractRange).kind == tyChar:
|
||||
result = ropef("((NU8)($1))", [result])
|
||||
result = "((NU8)($1))" % [result]
|
||||
|
||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
takeAddr: bool) =
|
||||
@@ -244,11 +246,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
discard
|
||||
of frHeader:
|
||||
var r = rdLoc(a)
|
||||
if not takeAddr: r = ropef("(*$1)", [r])
|
||||
if not takeAddr: r = "(*$1)" % [r]
|
||||
var s = skipTypes(t, abstractInst)
|
||||
if not p.module.compileToCpp:
|
||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||
app(r, ".Sup")
|
||||
add(r, ".Sup")
|
||||
s = skipTypes(s.sons[0], abstractInst)
|
||||
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
|
||||
of frEmbedded:
|
||||
@@ -276,7 +278,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
if containsGcRef:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, OnStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
nilLoc.r = rope("NIM_NIL")
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
|
||||
@@ -325,7 +327,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
inc(p.labels)
|
||||
result.r = con("LOC", toRope(p.labels))
|
||||
result.r = "LOC" & rope(p.labels)
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||
result.k = locTemp
|
||||
#result.a = - 1
|
||||
@@ -340,9 +342,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
# of interior pointers instead
|
||||
if optRefcGC notin gGlobalOptions: return
|
||||
var result: TLoc
|
||||
var fid = toRope(p.gcFrameId)
|
||||
result.r = con("GCFRAME.F", fid)
|
||||
appf(p.gcFrameType, " $1 F$2;$n",
|
||||
var fid = rope(p.gcFrameId)
|
||||
result.r = "GCFRAME.F" & fid
|
||||
addf(p.gcFrameType, " $1 F$2;$n",
|
||||
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
||||
inc(p.gcFrameId)
|
||||
result.k = locTemp
|
||||
@@ -359,10 +361,10 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
|
||||
|
||||
proc initGCFrame(p: BProc): PRope =
|
||||
if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType)
|
||||
proc initGCFrame(p: BProc): Rope =
|
||||
if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
|
||||
|
||||
proc deinitGCFrame(p: BProc): PRope =
|
||||
proc deinitGCFrame(p: BProc): Rope =
|
||||
if p.gcFrameId > 0:
|
||||
result = ropecg(p.module,
|
||||
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
|
||||
@@ -371,42 +373,42 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
|
||||
# XXX work around a bug: No type information for open arrays possible:
|
||||
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
|
||||
var a = con("&", s.loc.r)
|
||||
var a = "&" & s.loc.r
|
||||
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
|
||||
lineF(p, cpsInit,
|
||||
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
|
||||
[p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
|
||||
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
|
||||
genTypeInfo(p.module, s.loc.t)])
|
||||
inc(p.maxFrameLen)
|
||||
inc p.blocks[p.blocks.len-1].frameLen
|
||||
|
||||
proc localVarDecl(p: BProc; s: PSym): PRope =
|
||||
proc localVarDecl(p: BProc; s: PSym): Rope =
|
||||
if s.loc.k == locNone:
|
||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
result = getTypeDesc(p.module, s.loc.t)
|
||||
if s.constraint.isNil:
|
||||
if sfRegister in s.flags: app(result, " register")
|
||||
if sfRegister in s.flags: add(result, " register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# app(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags: app(result, " volatile")
|
||||
app(result, " ")
|
||||
app(result, s.loc.r)
|
||||
# add(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags: add(result, " volatile")
|
||||
add(result, " ")
|
||||
add(result, s.loc.r)
|
||||
else:
|
||||
result = ropef(s.cgDeclFrmt, result, s.loc.r)
|
||||
result = s.cgDeclFrmt % [result, s.loc.r]
|
||||
|
||||
proc assignLocalVar(p: BProc, s: PSym) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let decl = localVarDecl(p, s).con(";" & tnl)
|
||||
let decl = localVarDecl(p, s) & ";" & tnl
|
||||
line(p, cpsLocals, decl)
|
||||
localDebugInfo(p, s)
|
||||
|
||||
include ccgthreadvars
|
||||
|
||||
proc varInDynamicLib(m: BModule, sym: PSym)
|
||||
proc mangleDynLibProc(sym: PSym): PRope
|
||||
proc mangleDynLibProc(sym: PSym): Rope
|
||||
|
||||
proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
if s.loc.k == locNone:
|
||||
@@ -424,17 +426,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
if sfThread in s.flags:
|
||||
declareThreadVar(p.module, s, sfImportc in s.flags)
|
||||
else:
|
||||
var decl: PRope = nil
|
||||
var decl: Rope = nil
|
||||
var td = getTypeDesc(p.module, s.loc.t)
|
||||
if s.constraint.isNil:
|
||||
if sfImportc in s.flags: app(decl, "extern ")
|
||||
app(decl, td)
|
||||
if sfRegister in s.flags: app(decl, " register")
|
||||
if sfVolatile in s.flags: app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
if sfImportc in s.flags: add(decl, "extern ")
|
||||
add(decl, td)
|
||||
if sfRegister in s.flags: add(decl, " register")
|
||||
if sfVolatile in s.flags: add(decl, " volatile")
|
||||
addf(decl, " $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
|
||||
app(p.module.s[cfsVars], decl)
|
||||
decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
|
||||
add(p.module.s[cfsVars], decl)
|
||||
if p.withinLoop > 0:
|
||||
# fixes tests/run/tzeroarray:
|
||||
resetLoc(p, s.loc)
|
||||
@@ -455,7 +457,7 @@ proc fillProcLoc(sym: PSym) =
|
||||
|
||||
proc getLabel(p: BProc): TLabel =
|
||||
inc(p.labels)
|
||||
result = con("LA", toRope(p.labels))
|
||||
result = "LA" & rope(p.labels)
|
||||
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
lineF(p, cpsStmts, "$1: ;$n", [labl])
|
||||
@@ -467,9 +469,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
||||
proc intLiteral(i: BiggestInt): PRope
|
||||
proc genLiteral(p: BProc, n: PNode): PRope
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope
|
||||
proc intLiteral(i: BiggestInt): Rope
|
||||
proc genLiteral(p: BProc, n: PNode): Rope
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e.typ, OnUnknown)
|
||||
@@ -480,13 +482,13 @@ proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||
result.flags.incl lfSingleUse
|
||||
expr(p, e, result)
|
||||
|
||||
proc lenField(p: BProc): PRope =
|
||||
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
proc lenField(p: BProc): Rope =
|
||||
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
|
||||
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
|
||||
|
||||
# ----------------------------- dynamic library handling -----------------
|
||||
# We don't finalize dynamic libs as this does the OS for us.
|
||||
# We don't finalize dynamic libs as the OS does this for us.
|
||||
|
||||
proc isGetProcAddr(lib: PLib): bool =
|
||||
let n = lib.path
|
||||
@@ -500,16 +502,16 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
var tmp = getGlobalTempName()
|
||||
assert(lib.name == nil)
|
||||
lib.name = tmp # BUGFIX: cgsym has awful side-effects
|
||||
appf(m.s[cfsVars], "static void* $1;$n", [tmp])
|
||||
addf(m.s[cfsVars], "static void* $1;$n", [tmp])
|
||||
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
|
||||
var s: TStringSeq = @[]
|
||||
libCandidates(lib.path.strVal, s)
|
||||
if gVerbosity >= 2:
|
||||
msgWriteln("Dependency: " & lib.path.strVal)
|
||||
var loadlib: PRope = nil
|
||||
var loadlib: Rope = nil
|
||||
for i in countup(0, high(s)):
|
||||
inc(m.labels)
|
||||
if i > 0: app(loadlib, "||")
|
||||
if i > 0: add(loadlib, "||")
|
||||
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
|
||||
[tmp, getStrLit(m, s[i])])
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
@@ -520,21 +522,21 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
p.options = p.options - {optStackTrace, optEndb}
|
||||
var dest: TLoc
|
||||
initLocExpr(p, lib.path, dest)
|
||||
app(m.s[cfsVars], p.s(cpsLocals))
|
||||
app(m.s[cfsDynLibInit], p.s(cpsInit))
|
||||
app(m.s[cfsDynLibInit], p.s(cpsStmts))
|
||||
add(m.s[cfsVars], p.s(cpsLocals))
|
||||
add(m.s[cfsDynLibInit], p.s(cpsInit))
|
||||
add(m.s[cfsDynLibInit], p.s(cpsStmts))
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
|
||||
[tmp, rdLoc(dest)])
|
||||
|
||||
if lib.name == nil: internalError("loadDynamicLib")
|
||||
|
||||
proc mangleDynLibProc(sym: PSym): PRope =
|
||||
proc mangleDynLibProc(sym: PSym): Rope =
|
||||
if sfCompilerProc in sym.flags:
|
||||
# NOTE: sym.loc.r is the external name!
|
||||
result = toRope(sym.name.s)
|
||||
result = rope(sym.name.s)
|
||||
else:
|
||||
result = ropef("Dl_$1", [toRope(sym.id)])
|
||||
result = "Dl_$1" % [rope(sym.id)]
|
||||
|
||||
proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
@@ -549,30 +551,28 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
let n = lib.path
|
||||
var a: TLoc
|
||||
initLocExpr(m.initProc, n[0], a)
|
||||
var params = con(rdLoc(a), "(")
|
||||
var params = rdLoc(a) & "("
|
||||
for i in 1 .. n.len-2:
|
||||
initLocExpr(m.initProc, n[i], a)
|
||||
params.app(rdLoc(a))
|
||||
params.app(", ")
|
||||
let load = ropef("\t$1 = ($2) ($3$4));$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
params, makeCString(ropeToStr(extname))])
|
||||
params.add(rdLoc(a))
|
||||
params.add(", ")
|
||||
let load = "\t$1 = ($2) ($3$4));$n" %
|
||||
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
||||
internalAssert(last.kind == nkStrLit)
|
||||
let idx = last.strVal
|
||||
if idx.len == 0:
|
||||
app(m.initProc.s(cpsStmts), load)
|
||||
add(m.initProc.s(cpsStmts), load)
|
||||
elif idx.len == 1 and idx[0] in {'0'..'9'}:
|
||||
app(m.extensionLoaders[idx[0]], load)
|
||||
add(m.extensionLoaders[idx[0]], load)
|
||||
else:
|
||||
internalError(sym.info, "wrong index: " & idx)
|
||||
else:
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
lib.name, makeCString(ropeToStr(extname))])
|
||||
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
||||
addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
@@ -584,16 +584,15 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
inc(m.labels, 2)
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
lib.name, makeCString(ropeToStr(extname))])
|
||||
appf(m.s[cfsVars], "$2* $1;$n",
|
||||
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
||||
addf(m.s[cfsVars], "$2* $1;$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
sym.loc.r = mangleDynLibProc(sym)
|
||||
sym.typ.sym = nil # generate a new name
|
||||
|
||||
proc cgsym(m: BModule, name: string): PRope =
|
||||
proc cgsym(m: BModule, name: string): Rope =
|
||||
var sym = magicsys.getCompilerProc(name)
|
||||
if sym != nil:
|
||||
case sym.kind
|
||||
@@ -609,29 +608,29 @@ proc cgsym(m: BModule, name: string): PRope =
|
||||
result = sym.loc.r
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
|
||||
add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
|
||||
var it = PStrEntry(m.headerFiles.head)
|
||||
while it != nil:
|
||||
if it.data[0] notin {'\"', '<'}:
|
||||
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
|
||||
addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
|
||||
else:
|
||||
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
|
||||
addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc retIsNotVoid(s: PSym): bool =
|
||||
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
|
||||
|
||||
proc initFrame(p: BProc, procname, filename: PRope): PRope =
|
||||
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
if p.maxFrameLen > 0:
|
||||
discard cgsym(p.module, "TVarSlot")
|
||||
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
|
||||
procname, filename, p.maxFrameLen.toRope,
|
||||
p.blocks[0].frameLen.toRope)
|
||||
procname, filename, p.maxFrameLen.rope,
|
||||
p.blocks[0].frameLen.rope)
|
||||
else:
|
||||
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
|
||||
|
||||
proc deinitFrame(p: BProc): PRope =
|
||||
proc deinitFrame(p: BProc): Rope =
|
||||
result = rfmt(p.module, "\t#popFrame();$n")
|
||||
|
||||
proc closureSetup(p: BProc, prc: PSym) =
|
||||
@@ -650,7 +649,7 @@ proc closureSetup(p: BProc, prc: PSym) =
|
||||
proc genProcAux(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = genProcHeader(m, prc)
|
||||
var returnStmt: PRope = nil
|
||||
var returnStmt: Rope = nil
|
||||
assert(prc.ast != nil)
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
@@ -676,33 +675,33 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
assignParam(p, param)
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: PRope
|
||||
var generatedProc: Rope
|
||||
if sfPure in prc.flags:
|
||||
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
header = con("__declspec(naked) ", header)
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
|
||||
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
|
||||
else:
|
||||
generatedProc = rfmt(nil, "$N$1 {$N", header)
|
||||
app(generatedProc, initGCFrame(p))
|
||||
add(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
var procname = makeCString(prc.name.s)
|
||||
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
|
||||
add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
|
||||
else:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
appcg(p, cpsInit, "\t#nimProfile();$n", [])
|
||||
if p.beforeRetNeeded: app(generatedProc, "{")
|
||||
app(generatedProc, p.s(cpsInit))
|
||||
app(generatedProc, p.s(cpsStmts))
|
||||
if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n")
|
||||
app(generatedProc, deinitGCFrame(p))
|
||||
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
|
||||
app(generatedProc, returnStmt)
|
||||
app(generatedProc, ~"}$N")
|
||||
app(m.s[cfsProcs], generatedProc)
|
||||
if p.beforeRetNeeded: add(generatedProc, "{")
|
||||
add(generatedProc, p.s(cpsInit))
|
||||
add(generatedProc, p.s(cpsStmts))
|
||||
if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
|
||||
add(generatedProc, deinitGCFrame(p))
|
||||
if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
|
||||
add(generatedProc, returnStmt)
|
||||
add(generatedProc, ~"}$N")
|
||||
add(m.s[cfsProcs], generatedProc)
|
||||
|
||||
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = sfCompileToCpp in m.module.flags and
|
||||
@@ -715,15 +714,15 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if getModule(sym).id != m.module.id and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
|
||||
add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
|
||||
header = con("extern \"C\" ", header)
|
||||
header = "extern \"C\" " & header
|
||||
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
||||
header.app(" __attribute__((naked))")
|
||||
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
header.add(" __attribute__((naked))")
|
||||
add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
fillProcLoc(prc)
|
||||
@@ -760,16 +759,16 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
||||
var q = findPendingModule(m, sym)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, sym.id):
|
||||
assert q.initProc.module == q
|
||||
appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
|
||||
# declare header:
|
||||
if q != m and not containsOrIncl(m.declaredThings, sym.id):
|
||||
assert(sym.loc.r != nil)
|
||||
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
|
||||
[getTypeDesc(m, sym.loc.t), sym.loc.r])
|
||||
app(m.s[cfsData], headerDecl)
|
||||
let headerDecl = "extern NIM_CONST $1 $2;$n" %
|
||||
[getTypeDesc(m, sym.loc.t), sym.loc.r]
|
||||
add(m.s[cfsData], headerDecl)
|
||||
if sfExportc in sym.flags and generatedHeader != nil:
|
||||
app(generatedHeader.s[cfsData], headerDecl)
|
||||
add(generatedHeader.s[cfsData], headerDecl)
|
||||
|
||||
proc isActivated(prc: PSym): bool = prc.typ != nil
|
||||
|
||||
@@ -798,47 +797,47 @@ proc genVarPrototypeAux(m: BModule, sym: PSym) =
|
||||
if sfThread in sym.flags:
|
||||
declareThreadVar(m, sym, true)
|
||||
else:
|
||||
app(m.s[cfsVars], "extern ")
|
||||
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
|
||||
if lfDynamicLib in sym.loc.flags: app(m.s[cfsVars], "*")
|
||||
if sfRegister in sym.flags: app(m.s[cfsVars], " register")
|
||||
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
|
||||
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
|
||||
add(m.s[cfsVars], "extern ")
|
||||
add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
|
||||
if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
|
||||
if sfRegister in sym.flags: add(m.s[cfsVars], " register")
|
||||
if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
|
||||
addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
|
||||
|
||||
proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
genVarPrototypeAux(m, sym)
|
||||
|
||||
proc addIntTypes(result: var PRope) {.inline.} =
|
||||
appf(result, "#define NIM_INTBITS $1", [
|
||||
platform.CPU[targetCPU].intSize.toRope])
|
||||
proc addIntTypes(result: var Rope) {.inline.} =
|
||||
addf(result, "#define NIM_INTBITS $1", [
|
||||
platform.CPU[targetCPU].intSize.rope])
|
||||
|
||||
proc getCopyright(cfile: string): PRope =
|
||||
proc getCopyright(cfile: string): Rope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropef("/* Generated by Nim Compiler v$1 */$N" &
|
||||
result = ("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2015 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N",
|
||||
[toRope(VersionAsString)])
|
||||
"/* The generated code is subject to the original license. */$N") %
|
||||
[rope(VersionAsString)]
|
||||
else:
|
||||
result = ropef("/* Generated by Nim Compiler v$1 */$N" &
|
||||
result = ("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2015 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N" &
|
||||
"/* Compiled for: $2, $3, $4 */$N" &
|
||||
"/* Command for C compiler:$n $5 */$N",
|
||||
[toRope(VersionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||
toRope(getCompileCFileCmd(cfile))])
|
||||
"/* Command for C compiler:$n $5 */$N") %
|
||||
[rope(VersionAsString),
|
||||
rope(platform.OS[targetOS].name),
|
||||
rope(platform.CPU[targetCPU].name),
|
||||
rope(extccomp.CC[extccomp.cCompiler].name),
|
||||
rope(getCompileCFileCmd(cfile))]
|
||||
|
||||
proc getFileHeader(cfile: string): PRope =
|
||||
proc getFileHeader(cfile: string): Rope =
|
||||
result = getCopyright(cfile)
|
||||
addIntTypes(result)
|
||||
|
||||
proc genFilenames(m: BModule): PRope =
|
||||
proc genFilenames(m: BModule): Rope =
|
||||
discard cgsym(m, "dbgRegisterFilename")
|
||||
result = nil
|
||||
for i in 0.. <fileInfos.len:
|
||||
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
|
||||
result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString])
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
const
|
||||
@@ -920,7 +919,7 @@ proc genMainProc(m: BModule) =
|
||||
MainProcs &
|
||||
"}$N$N"
|
||||
|
||||
var nimMain, otherMain: TFormatStr
|
||||
var nimMain, otherMain: FormatStr
|
||||
if platform.targetOS == osWindows and
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in gGlobalOptions:
|
||||
@@ -941,10 +940,10 @@ proc genMainProc(m: BModule) =
|
||||
otherMain = PosixCMain
|
||||
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
|
||||
if optEndb in gOptions:
|
||||
gBreakpoints.app(m.genFilenames)
|
||||
gBreakpoints.add(m.genFilenames)
|
||||
|
||||
let initStackBottomCall =
|
||||
if platform.targetOS == osStandalone: "".toRope
|
||||
if platform.targetOS == osStandalone: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
@@ -952,56 +951,56 @@ proc genMainProc(m: BModule) =
|
||||
if emulatedThreadVars() and platform.targetOS != osStandalone:
|
||||
ropecg(m, "\t#initThreadVarsEmulation();$N")
|
||||
else:
|
||||
"".toRope,
|
||||
"".rope,
|
||||
initStackBottomCall])
|
||||
|
||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
|
||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, rope(m.labels)])
|
||||
if optNoMain notin gGlobalOptions:
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
|
||||
proc getSomeInitName(m: PSym, suffix: string): PRope =
|
||||
proc getSomeInitName(m: PSym, suffix: string): Rope =
|
||||
assert m.kind == skModule
|
||||
assert m.owner.kind == skPackage
|
||||
if {sfSystemModule, sfMainModule} * m.flags == {}:
|
||||
result = m.owner.name.s.mangle.toRope
|
||||
result.app "_"
|
||||
result.app m.name.s
|
||||
result.app suffix
|
||||
result = m.owner.name.s.mangle.rope
|
||||
result.add "_"
|
||||
result.add m.name.s
|
||||
result.add suffix
|
||||
|
||||
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
|
||||
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
|
||||
proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init")
|
||||
proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit")
|
||||
|
||||
proc registerModuleToMain(m: PSym) =
|
||||
var
|
||||
init = m.getInitName
|
||||
datInit = m.getDatInitName
|
||||
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
|
||||
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
|
||||
addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
|
||||
addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
|
||||
if sfSystemModule notin m.flags:
|
||||
appf(mainDatInit, "\t$1();$N", [datInit])
|
||||
let initCall = ropef("\t$1();$N", [init])
|
||||
addf(mainDatInit, "\t$1();$N", [datInit])
|
||||
let initCall = "\t$1();$N" % [init]
|
||||
if sfMainModule in m.flags:
|
||||
app(mainModInit, initCall)
|
||||
add(mainModInit, initCall)
|
||||
else:
|
||||
app(otherModsInit, initCall)
|
||||
add(otherModsInit, initCall)
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname = getInitName(m.module)
|
||||
var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname])
|
||||
var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
[m.typeNodesName, toRope(m.typeNodes)])
|
||||
[m.typeNodesName, rope(m.typeNodes)])
|
||||
if m.nimTypes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
|
||||
[m.nimTypesName, toRope(m.nimTypes)])
|
||||
[m.nimTypesName, rope(m.nimTypes)])
|
||||
|
||||
app(prc, initGCFrame(m.initProc))
|
||||
add(prc, initGCFrame(m.initProc))
|
||||
|
||||
app(prc, genSectionStart(cpsLocals))
|
||||
app(prc, m.preInitProc.s(cpsLocals))
|
||||
app(prc, m.initProc.s(cpsLocals))
|
||||
app(prc, m.postInitProc.s(cpsLocals))
|
||||
app(prc, genSectionEnd(cpsLocals))
|
||||
add(prc, genSectionStart(cpsLocals))
|
||||
add(prc, m.preInitProc.s(cpsLocals))
|
||||
add(prc, m.initProc.s(cpsLocals))
|
||||
add(prc, m.postInitProc.s(cpsLocals))
|
||||
add(prc, genSectionEnd(cpsLocals))
|
||||
|
||||
if optStackTrace in m.initProc.options and not m.frameDeclared:
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
@@ -1009,58 +1008,58 @@ proc genInitCode(m: BModule) =
|
||||
m.frameDeclared = true
|
||||
if not m.preventStackTrace:
|
||||
var procname = makeCString(m.module.name.s)
|
||||
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
else:
|
||||
app(prc, ~"\tTFrame F; F.len = 0;$N")
|
||||
add(prc, ~"\tTFrame F; F.len = 0;$N")
|
||||
|
||||
app(prc, genSectionStart(cpsInit))
|
||||
app(prc, m.preInitProc.s(cpsInit))
|
||||
app(prc, m.initProc.s(cpsInit))
|
||||
app(prc, m.postInitProc.s(cpsInit))
|
||||
app(prc, genSectionEnd(cpsInit))
|
||||
add(prc, genSectionStart(cpsInit))
|
||||
add(prc, m.preInitProc.s(cpsInit))
|
||||
add(prc, m.initProc.s(cpsInit))
|
||||
add(prc, m.postInitProc.s(cpsInit))
|
||||
add(prc, genSectionEnd(cpsInit))
|
||||
|
||||
app(prc, genSectionStart(cpsStmts))
|
||||
app(prc, m.preInitProc.s(cpsStmts))
|
||||
app(prc, m.initProc.s(cpsStmts))
|
||||
app(prc, m.postInitProc.s(cpsStmts))
|
||||
app(prc, genSectionEnd(cpsStmts))
|
||||
add(prc, genSectionStart(cpsStmts))
|
||||
add(prc, m.preInitProc.s(cpsStmts))
|
||||
add(prc, m.initProc.s(cpsStmts))
|
||||
add(prc, m.postInitProc.s(cpsStmts))
|
||||
add(prc, genSectionEnd(cpsStmts))
|
||||
if optStackTrace in m.initProc.options and not m.preventStackTrace:
|
||||
app(prc, deinitFrame(m.initProc))
|
||||
app(prc, deinitGCFrame(m.initProc))
|
||||
appf(prc, "}$N$N")
|
||||
add(prc, deinitFrame(m.initProc))
|
||||
add(prc, deinitGCFrame(m.initProc))
|
||||
addf(prc, "}$N$N", [])
|
||||
|
||||
prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
[getDatInitName(m.module)])
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
app(prc, genSectionStart(i))
|
||||
app(prc, m.s[i])
|
||||
app(prc, genSectionEnd(i))
|
||||
add(prc, genSectionStart(i))
|
||||
add(prc, m.s[i])
|
||||
add(prc, genSectionEnd(i))
|
||||
|
||||
appf(prc, "}$N$N")
|
||||
addf(prc, "}$N$N", [])
|
||||
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
|
||||
# that would lead to a *nesting* of merge sections which the merger does
|
||||
# not support. So we add it to another special section: ``cfsInitProc``
|
||||
app(m.s[cfsInitProc], prc)
|
||||
add(m.s[cfsInitProc], prc)
|
||||
|
||||
for i, el in pairs(m.extensionLoaders):
|
||||
if el != nil:
|
||||
let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N",
|
||||
(i.ord - '0'.ord).toRope, el)
|
||||
app(m.s[cfsInitProc], ex)
|
||||
let ex = "N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
|
||||
[(i.ord - '0'.ord).rope, el]
|
||||
add(m.s[cfsInitProc], ex)
|
||||
|
||||
proc genModule(m: BModule, cfile: string): PRope =
|
||||
proc genModule(m: BModule, cfile: string): Rope =
|
||||
result = getFileHeader(cfile)
|
||||
result.app(genMergeInfo(m))
|
||||
result.add(genMergeInfo(m))
|
||||
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
app(result, genSectionStart(i))
|
||||
app(result, m.s[i])
|
||||
app(result, genSectionEnd(i))
|
||||
app(result, m.s[cfsInitProc])
|
||||
add(result, genSectionStart(i))
|
||||
add(result, m.s[i])
|
||||
add(result, genSectionEnd(i))
|
||||
add(result, m.s[cfsInitProc])
|
||||
|
||||
proc newPreInitProc(m: BModule): BProc =
|
||||
result = newProc(nil, m)
|
||||
@@ -1172,22 +1171,22 @@ proc myOpen(module: PSym): PPassContext =
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
var result = getCopyright(m.filename)
|
||||
var guard = ropef("__$1__", m.filename.splitFile.name.toRope)
|
||||
result.appf("#ifndef $1$n#define $1$n", guard)
|
||||
var guard = "__$1__" % [m.filename.splitFile.name.rope]
|
||||
result.addf("#ifndef $1$n#define $1$n", [guard])
|
||||
addIntTypes(result)
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
app(result, genSectionStart(i))
|
||||
app(result, m.s[i])
|
||||
app(result, genSectionEnd(i))
|
||||
app(result, m.s[cfsInitProc])
|
||||
add(result, genSectionStart(i))
|
||||
add(result, m.s[i])
|
||||
add(result, genSectionEnd(i))
|
||||
add(result, m.s[cfsInitProc])
|
||||
|
||||
if optGenDynLib in gGlobalOptions:
|
||||
result.app("N_LIB_IMPORT ")
|
||||
result.appf("N_CDECL(void, NimMain)(void);$n")
|
||||
result.appf("#endif /* $1 */$n", guard)
|
||||
result.add("N_LIB_IMPORT ")
|
||||
result.addf("N_CDECL(void, NimMain)(void);$n", [])
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
writeRope(result, m.filename)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
@@ -1224,7 +1223,7 @@ proc finishModule(m: BModule) =
|
||||
dec(gForwardedProcsCounter, i)
|
||||
setLen(m.forwardedProcs, 0)
|
||||
|
||||
proc shouldRecompile(code: PRope, cfile: string): bool =
|
||||
proc shouldRecompile(code: Rope, cfile: string): bool =
|
||||
result = true
|
||||
if optForceFullMake notin gGlobalOptions:
|
||||
var objFile = toObjFile(cfile)
|
||||
@@ -1249,13 +1248,13 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
finishTypeDescriptions(m)
|
||||
if sfMainModule in m.module.flags:
|
||||
# generate main file:
|
||||
app(m.s[cfsProcHeaders], mainModProcs)
|
||||
add(m.s[cfsProcHeaders], mainModProcs)
|
||||
generateThreadVarsSize(m)
|
||||
|
||||
var code = genModule(m, cfile)
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
tccgen.compileCCode(ropeToStr(code))
|
||||
tccgen.compileCCode($code)
|
||||
return
|
||||
|
||||
if shouldRecompile(code, cfile):
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
from msgs import TLineInfo
|
||||
|
||||
type
|
||||
TLabel* = PRope # for the C generator a label is just a rope
|
||||
TLabel* = Rope # for the C generator a label is just a rope
|
||||
TCFileSection* = enum # the sections a generated C file consists of
|
||||
cfsMergeInfo, # section containing merge information
|
||||
cfsHeaders, # section for C include file headers
|
||||
@@ -45,17 +45,17 @@ type
|
||||
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
|
||||
ctCString
|
||||
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
|
||||
TCFileSections* = array[TCFileSection, Rope] # 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, PRope] # represents a generated C proc
|
||||
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
|
||||
BModule* = ref TCGen
|
||||
BProc* = ref TCProc
|
||||
TBlock*{.final.} = object
|
||||
id*: int # the ID of the label; positive means that it
|
||||
label*: PRope # generated text for the label
|
||||
label*: Rope # generated text for the label
|
||||
# nil if label is not used
|
||||
sections*: TCProcSections # the code beloging
|
||||
isLoop*: bool # whether block is a loop
|
||||
@@ -73,7 +73,7 @@ type
|
||||
inExceptBlock*: int # are we currently inside an except block?
|
||||
# leaving such scopes by raise or by return must
|
||||
# execute any applicable finally blocks
|
||||
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
|
||||
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
|
||||
# using return in finally statements
|
||||
labels*: Natural # for generating unique labels in the C proc
|
||||
blocks*: seq[TBlock] # nested blocks
|
||||
@@ -89,7 +89,7 @@ type
|
||||
# requires 'T x = T()' to become 'T x; x = T()'
|
||||
# (yes, C++ is weird like that)
|
||||
gcFrameId*: Natural # for the GC stack marking
|
||||
gcFrameType*: PRope # the struct {} we put the GC markers into
|
||||
gcFrameType*: Rope # the struct {} we put the GC markers into
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TCGen = object of TPassContext # represents a C source file
|
||||
@@ -118,24 +118,24 @@ type
|
||||
dataCache*: TNodeTable
|
||||
forwardedProcs*: TSymSeq # keep forwarded procs here
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
typeNodesName*, nimTypesName*: PRope # used for type info generation
|
||||
typeNodesName*, nimTypesName*: Rope # used for type info generation
|
||||
labels*: Natural # for generating unique module-scope names
|
||||
extensionLoaders*: array['0'..'9', PRope] # special procs for the
|
||||
extensionLoaders*: array['0'..'9', Rope] # special procs for the
|
||||
# OpenGL wrapper
|
||||
injectStmt*: PRope
|
||||
injectStmt*: Rope
|
||||
|
||||
var
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
|
||||
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
|
||||
# varuious parts of the main module
|
||||
gMapping*: PRope # the generated mapping file (if requested)
|
||||
gMapping*: Rope # the generated mapping file (if requested)
|
||||
gModules*: seq[BModule] = @[] # list of all compiled modules
|
||||
gForwardedProcsCounter*: int = 0
|
||||
|
||||
proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
|
||||
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# section in the current block
|
||||
result = p.blocks[p.blocks.len - 1].sections[s]
|
||||
|
||||
proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} =
|
||||
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# top level proc sections
|
||||
result = p.blocks[0].sections[s]
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
|
||||
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
|
||||
bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||
wordrecg, parseutils, nimblecmd, idents, parseopt
|
||||
|
||||
# but some have deps to imported modules. Yay.
|
||||
@@ -39,8 +39,8 @@ bootSwitch(usedFFI, hasFFI, "-d:useFFI")
|
||||
|
||||
proc writeCommandLineUsage*()
|
||||
|
||||
type
|
||||
TCmdLinePass* = enum
|
||||
type
|
||||
TCmdLinePass* = enum
|
||||
passCmd1, # first pass over the command line
|
||||
passCmd2, # second pass over the command line
|
||||
passPP # preprocessor called processCommand()
|
||||
@@ -54,35 +54,35 @@ const
|
||||
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2006-2015 by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
const
|
||||
Usage = slurp"doc/basicopt.txt".replace("//", "")
|
||||
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
|
||||
|
||||
proc getCommandLineDesc(): string =
|
||||
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
||||
proc getCommandLineDesc(): string =
|
||||
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]) & Usage
|
||||
|
||||
proc helpOnError(pass: TCmdLinePass) =
|
||||
proc helpOnError(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
msgWriteln(getCommandLineDesc())
|
||||
msgQuit(0)
|
||||
|
||||
proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||
proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]) & AdvancedUsage)
|
||||
msgQuit(0)
|
||||
|
||||
proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]))
|
||||
|
||||
discard """const gitHash = gorge("git log -n 1 --format=%H")
|
||||
if gitHash.strip.len == 40:
|
||||
msgWriteln("git hash: " & gitHash)"""
|
||||
const gitHash = gorge("git log -n 1 --format=%H").strip
|
||||
when gitHash.len == 40:
|
||||
msgWriteln("git hash: " & gitHash)
|
||||
|
||||
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
||||
@@ -92,8 +92,8 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
var
|
||||
helpWritten: bool
|
||||
|
||||
proc writeCommandLineUsage() =
|
||||
if not helpWritten:
|
||||
proc writeCommandLineUsage() =
|
||||
if not helpWritten:
|
||||
msgWriteln(getCommandLineDesc())
|
||||
helpWritten = true
|
||||
|
||||
@@ -101,51 +101,51 @@ proc addPrefix(switch: string): string =
|
||||
if len(switch) == 1: result = "-" & switch
|
||||
else: result = "--" & switch
|
||||
|
||||
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
||||
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
||||
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
|
||||
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
|
||||
|
||||
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
cmd = ""
|
||||
var i = 0
|
||||
if i < len(switch) and switch[i] == '-': inc(i)
|
||||
if i < len(switch) and switch[i] == '-': inc(i)
|
||||
while i < len(switch):
|
||||
while i < len(switch):
|
||||
case switch[i]
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
|
||||
else: break
|
||||
else: break
|
||||
inc(i)
|
||||
if i >= len(switch): arg = ""
|
||||
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
||||
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
|
||||
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case whichKeyword(arg)
|
||||
of wOn: gOptions = gOptions + op
|
||||
of wOff: gOptions = gOptions - op
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
|
||||
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case whichKeyword(arg)
|
||||
of wOn: gGlobalOptions = gGlobalOptions + op
|
||||
of wOff: gGlobalOptions = gGlobalOptions - op
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
|
||||
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
|
||||
|
||||
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
|
||||
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string) =
|
||||
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string) =
|
||||
var id = "" # arg = "X]:on|off"
|
||||
var i = 0
|
||||
var n = hintMin
|
||||
while i < len(arg) and (arg[i] != ']'):
|
||||
while i < len(arg) and (arg[i] != ']'):
|
||||
add(id, arg[i])
|
||||
inc(i)
|
||||
if i < len(arg) and (arg[i] == ']'): inc(i)
|
||||
@@ -165,7 +165,7 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
of wOff: excl(gNotes, n)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processCompile(filename: string) =
|
||||
proc processCompile(filename: string) =
|
||||
var found = findFile(filename)
|
||||
if found == "": found = filename
|
||||
var trunc = changeFileExt(found, "")
|
||||
@@ -191,7 +191,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
case switch.normalize
|
||||
of "debuginfo": result = contains(gGlobalOptions, optCDebug)
|
||||
of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
|
||||
@@ -228,11 +228,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
of "patterns": result = contains(gOptions, optPatterns)
|
||||
of "experimental": result = gExperimentalMode
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
|
||||
proc processPath(path: string, notRelativeToProj = false): string =
|
||||
let p = if notRelativeToProj or os.isAbsolute(path) or
|
||||
'$' in path or path[0] == '.':
|
||||
path
|
||||
'$' in path or path[0] == '.':
|
||||
path
|
||||
else:
|
||||
options.gProjectPath / path
|
||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
|
||||
@@ -251,14 +251,14 @@ proc trackDirty(arg: string, info: TLineInfo) =
|
||||
localError(info, errInvalidNumber, a[1])
|
||||
if parseUtils.parseInt(a[3], column) <= 0:
|
||||
localError(info, errInvalidNumber, a[2])
|
||||
|
||||
|
||||
let dirtyOriginalIdx = a[1].fileInfoIdx
|
||||
if dirtyOriginalIdx >= 0:
|
||||
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
|
||||
|
||||
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
||||
|
||||
proc track(arg: string, info: TLineInfo) =
|
||||
proc track(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
|
||||
var line, column: int
|
||||
@@ -273,13 +273,13 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.inclDynlibOverride(arg)
|
||||
|
||||
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
var
|
||||
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
var
|
||||
theOS: TSystemOS
|
||||
cpu: TSystemCPU
|
||||
key, val: string
|
||||
case switch.normalize
|
||||
of "path", "p":
|
||||
of "path", "p":
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg), info)
|
||||
of "nimblepath", "babelpath":
|
||||
@@ -303,7 +303,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "nimcache":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.nimcacheDir = processPath(arg)
|
||||
of "out", "o":
|
||||
of "out", "o":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.outFile = arg
|
||||
of "docseesrcurl":
|
||||
@@ -311,19 +311,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
options.docSeeSrcUrl = arg
|
||||
of "mainmodule", "m":
|
||||
discard "allow for backwards compatibility, but don't do anything"
|
||||
of "define", "d":
|
||||
of "define", "d":
|
||||
expectArg(switch, arg, pass, info)
|
||||
defineSymbol(arg)
|
||||
of "undef", "u":
|
||||
of "undef", "u":
|
||||
expectArg(switch, arg, pass, info)
|
||||
undefSymbol(arg)
|
||||
of "symbol":
|
||||
expectArg(switch, arg, pass, info)
|
||||
declareSymbol(arg)
|
||||
of "compile":
|
||||
declareSymbol(arg)
|
||||
of "compile":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: processCompile(arg)
|
||||
of "link":
|
||||
of "link":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: addFileToLink(arg)
|
||||
of "debuginfo":
|
||||
@@ -332,25 +332,25 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "embedsrc":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optEmbedOrigSrc)
|
||||
of "compileonly", "c":
|
||||
of "compileonly", "c":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optCompileOnly)
|
||||
of "nolinking":
|
||||
of "nolinking":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optNoLinking)
|
||||
of "nomain":
|
||||
of "nomain":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optNoMain)
|
||||
of "forcebuild", "f":
|
||||
of "forcebuild", "f":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optForceFullMake)
|
||||
of "project":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
gWholeProject = true
|
||||
of "gc":
|
||||
of "gc":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
of "boehm":
|
||||
of "boehm":
|
||||
gSelectedGC = gcBoehm
|
||||
defineSymbol("boehmgc")
|
||||
of "refc":
|
||||
@@ -388,7 +388,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
undefSymbol("endb")
|
||||
else:
|
||||
localError(info, "expected endb|gdb but found " & arg)
|
||||
of "profiler":
|
||||
of "profiler":
|
||||
processOnOffSwitch({optProfiler}, arg, pass, info)
|
||||
if optProfiler in gOptions: defineSymbol("profiler")
|
||||
else: undefSymbol("profiler")
|
||||
@@ -407,7 +407,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of "threads":
|
||||
processOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
|
||||
#if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
|
||||
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
|
||||
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
|
||||
of "implicitstatic":
|
||||
@@ -417,17 +417,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "opt":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
of "speed":
|
||||
of "speed":
|
||||
incl(gOptions, optOptimizeSpeed)
|
||||
excl(gOptions, optOptimizeSize)
|
||||
of "size":
|
||||
of "size":
|
||||
excl(gOptions, optOptimizeSpeed)
|
||||
incl(gOptions, optOptimizeSize)
|
||||
of "none":
|
||||
excl(gOptions, optOptimizeSpeed)
|
||||
excl(gOptions, optOptimizeSize)
|
||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
of "app":
|
||||
of "app":
|
||||
expectArg(switch, arg, pass, info)
|
||||
case arg.normalize
|
||||
of "gui":
|
||||
@@ -449,10 +449,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
defineSymbol("library")
|
||||
defineSymbol("staticlib")
|
||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
||||
of "passc", "t":
|
||||
of "passc", "t":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
|
||||
of "passl", "l":
|
||||
of "passl", "l":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
|
||||
of "cincludes":
|
||||
@@ -475,52 +475,52 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "include":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: implicitIncludes.add arg
|
||||
of "listcmd":
|
||||
of "listcmd":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optListCmd)
|
||||
of "genmapping":
|
||||
of "genmapping":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optGenMapping)
|
||||
of "os":
|
||||
of "os":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
if pass in {passCmd1, passPP}:
|
||||
theOS = platform.nameToOS(arg)
|
||||
if theOS == osNone: localError(info, errUnknownOS, arg)
|
||||
elif theOS != platform.hostOS:
|
||||
elif theOS != platform.hostOS:
|
||||
setTarget(theOS, targetCPU)
|
||||
condsyms.initDefines()
|
||||
of "cpu":
|
||||
of "cpu":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd1, passPP}:
|
||||
if pass in {passCmd1, passPP}:
|
||||
cpu = platform.nameToCPU(arg)
|
||||
if cpu == cpuNone: localError(info, errUnknownCPU, arg)
|
||||
elif cpu != platform.hostCPU:
|
||||
elif cpu != platform.hostCPU:
|
||||
setTarget(targetOS, cpu)
|
||||
condsyms.initDefines()
|
||||
of "run", "r":
|
||||
of "run", "r":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optRun)
|
||||
of "verbosity":
|
||||
of "verbosity":
|
||||
expectArg(switch, arg, pass, info)
|
||||
gVerbosity = parseInt(arg)
|
||||
of "parallelbuild":
|
||||
of "parallelbuild":
|
||||
expectArg(switch, arg, pass, info)
|
||||
gNumberOfProcessors = parseInt(arg)
|
||||
of "version", "v":
|
||||
of "version", "v":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
writeVersionInfo(pass)
|
||||
of "advanced":
|
||||
of "advanced":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
writeAdvancedUsage(pass)
|
||||
of "help", "h":
|
||||
of "help", "h":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
helpOnError(pass)
|
||||
of "symbolfiles":
|
||||
of "symbolfiles":
|
||||
processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
|
||||
of "skipcfg":
|
||||
of "skipcfg":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optSkipConfigFile)
|
||||
of "skipprojcfg":
|
||||
of "skipprojcfg":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optSkipProjConfigFile)
|
||||
of "skipusercfg":
|
||||
@@ -529,17 +529,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "skipparentcfg":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optSkipParentConfigFiles)
|
||||
of "genscript":
|
||||
of "genscript":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optGenScript)
|
||||
of "lib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
libpath = processPath(arg, notRelativeToProj=true)
|
||||
of "putenv":
|
||||
of "putenv":
|
||||
expectArg(switch, arg, pass, info)
|
||||
splitSwitch(arg, key, val, pass, info)
|
||||
os.putEnv(key, val)
|
||||
of "cc":
|
||||
of "cc":
|
||||
expectArg(switch, arg, pass, info)
|
||||
setCC(arg)
|
||||
of "track":
|
||||
@@ -548,7 +548,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "trackdirty":
|
||||
expectArg(switch, arg, pass, info)
|
||||
trackDirty(arg, info)
|
||||
of "suggest":
|
||||
of "suggest":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
gIdeCmd = ideSug
|
||||
of "def":
|
||||
@@ -584,7 +584,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
||||
|
||||
proc processCommand(switch: string, pass: TCmdLinePass) =
|
||||
var cmd, arg: string
|
||||
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
||||
@@ -600,14 +600,14 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
|
||||
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
||||
# we fix this here
|
||||
var bracketLe = strutils.find(p.key, '[')
|
||||
if bracketLe >= 0:
|
||||
if bracketLe >= 0:
|
||||
var key = substr(p.key, 0, bracketLe - 1)
|
||||
var val = substr(p.key, bracketLe + 1) & ':' & p.val
|
||||
processSwitch(key, val, pass, gCmdLineInfo)
|
||||
else:
|
||||
else:
|
||||
processSwitch(p.key, p.val, pass, gCmdLineInfo)
|
||||
|
||||
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
argsCount: var int): bool =
|
||||
if argsCount == 0:
|
||||
options.command = p.key
|
||||
|
||||
@@ -9,41 +9,41 @@
|
||||
|
||||
# This module implements a dependency file generator.
|
||||
|
||||
import
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, importer
|
||||
|
||||
proc generateDot*(project: string)
|
||||
|
||||
type
|
||||
type
|
||||
TGen = object of TPassContext
|
||||
module*: PSym
|
||||
PGen = ref TGen
|
||||
|
||||
var gDotGraph: PRope # the generated DOT file; we need a global variable
|
||||
var gDotGraph: Rope # the generated DOT file; we need a global variable
|
||||
|
||||
proc addDependencyAux(importing, imported: string) =
|
||||
appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)])
|
||||
proc addDependencyAux(importing, imported: string) =
|
||||
addf(gDotGraph, "$1 -> $2;$n", [rope(importing), rope(imported)])
|
||||
# s1 -> s2_4[label="[0-9]"];
|
||||
|
||||
proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
|
||||
proc addDotDependency(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
case n.kind
|
||||
of nkImportStmt:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkImportStmt:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var imported = getModuleName(n.sons[i])
|
||||
addDependencyAux(g.module.name.s, imported)
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
of nkFromStmt, nkImportExceptStmt:
|
||||
var imported = getModuleName(n.sons[0])
|
||||
addDependencyAux(g.module.name.s, imported)
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
|
||||
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
|
||||
else:
|
||||
else:
|
||||
discard
|
||||
|
||||
proc generateDot(project: string) =
|
||||
writeRope(ropef("digraph $1 {$n$2}$n", [
|
||||
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
|
||||
proc generateDot(project: string) =
|
||||
writeRope("digraph $1 {$n$2}$n" % [
|
||||
rope(changeFileExt(extractFilename(project), "")), gDotGraph],
|
||||
changeFileExt(project, "dot"))
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
|
||||
@@ -17,9 +17,9 @@ import
|
||||
importer, sempass2, json, xmltree, cgi, typesrenderer
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, PRope]
|
||||
TSections = array[TSymKind, Rope]
|
||||
TDocumentor = object of rstgen.TRstGenerator
|
||||
modDesc: PRope # module description
|
||||
modDesc: Rope # module description
|
||||
id: int # for generating IDs
|
||||
toc, section: TSections
|
||||
indexValFilename: string
|
||||
@@ -82,9 +82,9 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
|
||||
proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
|
||||
if gCmd != cmdRst2tex: appf(dest, xml, args)
|
||||
else: appf(dest, tex, args)
|
||||
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if gCmd != cmdRst2tex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
@@ -92,8 +92,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
return i
|
||||
result = -1
|
||||
|
||||
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
varvalues: openArray[PRope]): PRope =
|
||||
proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
|
||||
varvalues: openArray[Rope]): Rope =
|
||||
var i = 0
|
||||
var L = len(frmt)
|
||||
result = nil
|
||||
@@ -103,11 +103,11 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '#':
|
||||
app(result, varvalues[num])
|
||||
add(result, varvalues[num])
|
||||
inc(num)
|
||||
inc(i)
|
||||
of '$':
|
||||
app(result, "$")
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
@@ -117,7 +117,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
|
||||
num = j
|
||||
app(result, varvalues[j - 1])
|
||||
add(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
var id = ""
|
||||
while true:
|
||||
@@ -125,7 +125,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
inc(i)
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
of '{':
|
||||
var id = ""
|
||||
@@ -137,14 +137,14 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
inc(i) # skip }
|
||||
# search for the variable:
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
else: internalError("ropeFormatNamedVars")
|
||||
var start = i
|
||||
while i < L:
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start: app(result, substr(frmt, start, i - 1))
|
||||
if i - 1 >= start: add(result, substr(frmt, start, i - 1))
|
||||
|
||||
proc genComment(d: PDoc, n: PNode): string =
|
||||
result = ""
|
||||
@@ -154,9 +154,9 @@ proc genComment(d: PDoc, n: PNode): string =
|
||||
toLinenumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options + {roSkipPounds}), result)
|
||||
|
||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||
proc genRecComment(d: PDoc, n: PNode): Rope =
|
||||
if n == nil: return nil
|
||||
result = genComment(d, n).toRope
|
||||
result = genComment(d, n).rope
|
||||
if result == nil:
|
||||
if n.kind notin {nkEmpty..nkNilLit}:
|
||||
for i in countup(0, len(n)-1):
|
||||
@@ -331,9 +331,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
if not isVisible(nameNode): return
|
||||
let
|
||||
name = getName(d, nameNode)
|
||||
nameRope = name.toRope
|
||||
nameRope = name.rope
|
||||
plainDocstring = getPlainDocstring(n) # call here before genRecComment!
|
||||
var result: PRope = nil
|
||||
var result: Rope = nil
|
||||
var literal, plainName = ""
|
||||
var kind = tkEof
|
||||
var comm = genRecComment(d, n) # call this here for the side-effect!
|
||||
@@ -356,69 +356,69 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
[rope(esc(d.target, literal))])
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
[toRope(literal)])
|
||||
[rope(literal)])
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
|
||||
"\\spanStringLit{$1}", [rope(esc(d.target, literal))])
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
"\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
|
||||
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
|
||||
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
app(result, literal)
|
||||
add(result, literal)
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[toRope(esc(d.target, literal))])
|
||||
[rope(esc(d.target, literal))])
|
||||
inc(d.id)
|
||||
let
|
||||
plainNameRope = toRope(xmltree.escape(plainName.strip))
|
||||
plainNameRope = rope(xmltree.escape(plainName.strip))
|
||||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||
plainSymbolRope = toRope(cleanPlainSymbol)
|
||||
plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
|
||||
itemIDRope = toRope(d.id)
|
||||
plainSymbolRope = rope(cleanPlainSymbol)
|
||||
plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol))
|
||||
itemIDRope = rope(d.id)
|
||||
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
||||
symbolOrIdRope = symbolOrId.toRope
|
||||
symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
|
||||
symbolOrIdRope = symbolOrId.rope
|
||||
symbolOrIdEncRope = encodeUrl(symbolOrId).rope
|
||||
|
||||
var seeSrcRope: PRope = nil
|
||||
var seeSrcRope: Rope = nil
|
||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
|
||||
# XXX toFilename doesn't really work. We need to ensure that this keeps
|
||||
# returning a relative path.
|
||||
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
|
||||
["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
|
||||
["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
|
||||
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
|
||||
["path", "line", "url"], [n.info.toFilename.toRope,
|
||||
toRope($n.info.line), urlRope])])
|
||||
["path", "line", "url"], [n.info.toFilename.rope,
|
||||
rope($n.info.line), urlRope])])
|
||||
|
||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
|
||||
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
|
||||
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
|
||||
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
|
||||
[toRope(getName(d, nameNode, d.splitAfter)), result, comm,
|
||||
[rope(getName(d, nameNode, d.splitAfter)), result, comm,
|
||||
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
|
||||
plainSymbolEncRope, symbolOrIdEncRope]))
|
||||
|
||||
@@ -436,7 +436,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
if not isVisible(nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
comm = genRecComment(d, n).ropeToStr()
|
||||
comm = $genRecComment(d, n)
|
||||
r: TSrcGen
|
||||
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
@@ -453,14 +453,14 @@ proc checkForFalse(n: PNode): bool =
|
||||
|
||||
proc traceDeps(d: PDoc, n: PNode) =
|
||||
const k = skModule
|
||||
if d.section[k] != nil: app(d.section[k], ", ")
|
||||
if d.section[k] != nil: add(d.section[k], ", ")
|
||||
dispA(d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
"$1", [toRope(getModuleName(n))])
|
||||
"$1", [rope(getModuleName(n))])
|
||||
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
of nkCommentStmt: app(d.modDesc, genComment(d, n))
|
||||
of nkCommentStmt: add(d.modDesc, genComment(d, n))
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
genItem(d, n, n.sons[namePos], skProc)
|
||||
@@ -540,28 +540,28 @@ proc genSection(d: PDoc, kind: TSymKind) =
|
||||
"Iterators", "Iterators", "Converters", "Macros", "Templates"
|
||||
]
|
||||
if d.section[kind] == nil: return
|
||||
var title = sectionNames[kind].toRope
|
||||
var title = sectionNames[kind].rope
|
||||
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).toRope, title, toRope(ord(kind) + 50), d.section[kind]])
|
||||
ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
|
||||
d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
|
||||
ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
|
||||
|
||||
proc genOutFile(d: PDoc): PRope =
|
||||
proc genOutFile(d: PDoc): Rope =
|
||||
var
|
||||
code, content: PRope
|
||||
code, content: Rope
|
||||
title = ""
|
||||
var j = 0
|
||||
var tmp = ""
|
||||
renderTocEntries(d[], j, 1, tmp)
|
||||
var toc = tmp.toRope
|
||||
var toc = tmp.rope
|
||||
for i in countup(low(TSymKind), high(TSymKind)):
|
||||
genSection(d, i)
|
||||
app(toc, d.toc[i])
|
||||
add(toc, d.toc[i])
|
||||
if toc != nil:
|
||||
toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
|
||||
for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
|
||||
for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
|
||||
|
||||
# Extract the title. Non API modules generate an entry in the index table.
|
||||
if d.meta[metaTitle].len != 0:
|
||||
@@ -574,16 +574,16 @@ proc genOutFile(d: PDoc): PRope =
|
||||
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time", "content"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), code])
|
||||
[title.rope, toc, d.modDesc, rope(getDateStr()),
|
||||
rope(getClockStr()), code])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version", "analytics"],
|
||||
[title.toRope, toc, d.modDesc, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
|
||||
d.meta[metaVersion].toRope, d.analytics.toRope])
|
||||
[title.rope, toc, d.modDesc, rope(getDateStr()),
|
||||
rope(getClockStr()), content, d.meta[metaAuthor].rope,
|
||||
d.meta[metaVersion].rope, d.analytics.rope])
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
@@ -618,7 +618,7 @@ proc commandRstAux(filename, outExt: string) =
|
||||
#d.modDesc = newMutableRope(30_000)
|
||||
renderRstToOut(d[], rst, modDesc)
|
||||
#freezeMutableRope(d.modDesc)
|
||||
d.modDesc = toRope(modDesc)
|
||||
d.modDesc = rope(modDesc)
|
||||
writeOutput(d, filename, outExt)
|
||||
generateIndex(d)
|
||||
|
||||
@@ -635,7 +635,7 @@ proc commandJSON*() =
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
var json = generateJson(d, ast)
|
||||
var content = newRope(pretty(json))
|
||||
var content = rope(pretty(json))
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
@@ -644,12 +644,12 @@ proc commandJSON*() =
|
||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||
|
||||
proc commandBuildIndex*() =
|
||||
var content = mergeIndexes(gProjectFull).toRope
|
||||
var content = mergeIndexes(gProjectFull).rope
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version", "analytics"],
|
||||
["Index".toRope, nil, nil, toRope(getDateStr()),
|
||||
toRope(getClockStr()), content, nil, nil, nil])
|
||||
["Index".rope, nil, nil, rope(getDateStr()),
|
||||
rope(getClockStr()), content, nil, nil, nil])
|
||||
# no analytics because context is not available
|
||||
writeRope(code, getOutFile("theindex", HtmlExt))
|
||||
|
||||
@@ -449,7 +449,7 @@ proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||
if execWithEcho(cmd, prettyCmd) != 0:
|
||||
rawMessage(errExecutionOfProgramFailed, "")
|
||||
|
||||
proc generateScript(projectFile: string, script: PRope) =
|
||||
proc generateScript(projectFile: string, script: Rope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
writeRope(script, dir / addFileExt("compile_" & name,
|
||||
platform.OS[targetOS].scriptExt))
|
||||
@@ -604,7 +604,7 @@ proc addExternalFileToCompile*(filename: string) =
|
||||
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
||||
appendStr(externalToCompile, filename)
|
||||
|
||||
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
|
||||
prettyCmds: var TStringSeq, isExternal: bool) =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
@@ -615,8 +615,8 @@ proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
let (dir, name, ext) = splitFile(it.data)
|
||||
add(prettyCmds, "CC: " & name)
|
||||
if optGenScript in gGlobalOptions:
|
||||
app(script, compileCmd)
|
||||
app(script, tnl)
|
||||
add(script, compileCmd)
|
||||
add(script, tnl)
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc callCCompiler*(projectfile: string) =
|
||||
@@ -627,7 +627,7 @@ proc callCCompiler*(projectfile: string) =
|
||||
# generated
|
||||
fileCounter = 0
|
||||
var c = cCompiler
|
||||
var script: PRope = nil
|
||||
var script: Rope = nil
|
||||
var cmds: TStringSeq = @[]
|
||||
var prettyCmds: TStringSeq = @[]
|
||||
let prettyCb = proc (idx: int) =
|
||||
@@ -710,30 +710,30 @@ proc callCCompiler*(projectfile: string) =
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
app(script, linkCmd)
|
||||
app(script, tnl)
|
||||
add(script, linkCmd)
|
||||
add(script, tnl)
|
||||
generateScript(projectfile, script)
|
||||
|
||||
proc genMappingFiles(list: TLinkedList): PRope =
|
||||
proc genMappingFiles(list: TLinkedList): Rope =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
|
||||
addf(result, "--file:r\"$1\"$N", [rope(it.data)])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc writeMapping*(gSymbolMapping: PRope) =
|
||||
proc writeMapping*(gSymbolMapping: Rope) =
|
||||
if optGenMapping notin gGlobalOptions: return
|
||||
var code = toRope("[C_Files]\n")
|
||||
app(code, genMappingFiles(toCompile))
|
||||
app(code, genMappingFiles(externalToCompile))
|
||||
app(code, "\n[C_Compiler]\nFlags=")
|
||||
app(code, strutils.escape(getCompileOptions()))
|
||||
var code = rope("[C_Files]\n")
|
||||
add(code, genMappingFiles(toCompile))
|
||||
add(code, genMappingFiles(externalToCompile))
|
||||
add(code, "\n[C_Compiler]\nFlags=")
|
||||
add(code, strutils.escape(getCompileOptions()))
|
||||
|
||||
app(code, "\n[Linker]\nFlags=")
|
||||
app(code, strutils.escape(getLinkOptions() & " " &
|
||||
add(code, "\n[Linker]\nFlags=")
|
||||
add(code, strutils.escape(getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")))
|
||||
|
||||
app(code, "\n[Environment]\nlibpath=")
|
||||
app(code, strutils.escape(libpath))
|
||||
add(code, "\n[Environment]\nlibpath=")
|
||||
add(code, strutils.escape(libpath))
|
||||
|
||||
appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
|
||||
addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
|
||||
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
|
||||
|
||||
@@ -22,7 +22,8 @@ const
|
||||
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
mLtCh, mLtB, mLtPtr, mLtStr}
|
||||
|
||||
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
|
||||
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
|
||||
mXLenStr, mXLenSeq}
|
||||
|
||||
someIn = {mInRange, mInSet}
|
||||
|
||||
@@ -34,8 +35,8 @@ const
|
||||
someMul = {mMulI, mMulI64, mMulF64}
|
||||
someDiv = {mDivI, mDivI64, mDivF64}
|
||||
someMod = {mModI, mModI64}
|
||||
someMax = {mMaxI, mMaxI64, mMaxF64}
|
||||
someMin = {mMinI, mMinI64, mMinF64}
|
||||
someMax = {mMaxI, mMaxF64}
|
||||
someMin = {mMinI, mMinF64}
|
||||
|
||||
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
|
||||
proc isLocation(n: PNode): bool = not n.isValue
|
||||
|
||||
@@ -62,7 +62,7 @@ Files: "icons/koch_icon.o"
|
||||
|
||||
Files: "compiler/readme.txt"
|
||||
Files: "compiler/installer.ini"
|
||||
Files: "compiler/nim.nimrod.cfg"
|
||||
Files: "compiler/nim.nim.cfg"
|
||||
Files: "compiler/*.nim"
|
||||
Files: "doc/*.txt"
|
||||
Files: "doc/manual/*.txt"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,138 +9,138 @@
|
||||
|
||||
## Type info generation for the JS backend.
|
||||
|
||||
proc genTypeInfo(p: PProc, typ: PType): PRope
|
||||
proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
|
||||
var
|
||||
s, u: PRope
|
||||
proc genTypeInfo(p: PProc, typ: PType): Rope
|
||||
proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||
var
|
||||
s, u: Rope
|
||||
length: int
|
||||
field: PSym
|
||||
b: PNode
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
of nkRecList:
|
||||
length = sonsLen(n)
|
||||
if length == 1:
|
||||
if length == 1:
|
||||
result = genObjectFields(p, typ, n.sons[0])
|
||||
else:
|
||||
else:
|
||||
s = nil
|
||||
for i in countup(0, length - 1):
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
app(s, genObjectFields(p, typ, n.sons[i]))
|
||||
result = ropef("{kind: 2, len: $1, offset: 0, " &
|
||||
"typ: null, name: null, sons: [$2]}", [toRope(length), s])
|
||||
of nkSym:
|
||||
for i in countup(0, length - 1):
|
||||
if i > 0: add(s, ", " & tnl)
|
||||
add(s, genObjectFields(p, typ, n.sons[i]))
|
||||
result = ("{kind: 2, len: $1, offset: 0, " &
|
||||
"typ: null, name: null, sons: [$2]}") % [rope(length), s]
|
||||
of nkSym:
|
||||
field = n.sym
|
||||
s = genTypeInfo(p, field.typ)
|
||||
result = ropef("{kind: 1, offset: \"$1\", len: 0, " &
|
||||
"typ: $2, name: $3, sons: null}",
|
||||
[mangleName(field), s, makeJSString(field.name.s)])
|
||||
of nkRecCase:
|
||||
result = ("{kind: 1, offset: \"$1\", len: 0, " &
|
||||
"typ: $2, name: $3, sons: null}") %
|
||||
[mangleName(field), s, makeJSString(field.name.s)]
|
||||
of nkRecCase:
|
||||
length = sonsLen(n)
|
||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
|
||||
field = n.sons[0].sym
|
||||
s = genTypeInfo(p, field.typ)
|
||||
for i in countup(1, length - 1):
|
||||
for i in countup(1, length - 1):
|
||||
b = n.sons[i] # branch
|
||||
u = nil
|
||||
case b.kind
|
||||
of nkOfBranch:
|
||||
if sonsLen(b) < 2:
|
||||
of nkOfBranch:
|
||||
if sonsLen(b) < 2:
|
||||
internalError(b.info, "genObjectFields; nkOfBranch broken")
|
||||
for j in countup(0, sonsLen(b) - 2):
|
||||
if u != nil: app(u, ", ")
|
||||
if b.sons[j].kind == nkRange:
|
||||
appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])),
|
||||
toRope(getOrdValue(b.sons[j].sons[1]))])
|
||||
else:
|
||||
app(u, toRope(getOrdValue(b.sons[j])))
|
||||
of nkElse:
|
||||
u = toRope(lengthOrd(field.typ))
|
||||
for j in countup(0, sonsLen(b) - 2):
|
||||
if u != nil: add(u, ", ")
|
||||
if b.sons[j].kind == nkRange:
|
||||
addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
|
||||
rope(getOrdValue(b.sons[j].sons[1]))])
|
||||
else:
|
||||
add(u, rope(getOrdValue(b.sons[j])))
|
||||
of nkElse:
|
||||
u = rope(lengthOrd(field.typ))
|
||||
else: internalError(n.info, "genObjectFields(nkRecCase)")
|
||||
if result != nil: app(result, ", " & tnl)
|
||||
appf(result, "[SetConstr($1), $2]",
|
||||
if result != nil: add(result, ", " & tnl)
|
||||
addf(result, "[SetConstr($1), $2]",
|
||||
[u, genObjectFields(p, typ, lastSon(b))])
|
||||
result = ropef("{kind: 3, offset: \"$1\", len: $3, " &
|
||||
"typ: $2, name: $4, sons: [$5]}", [mangleName(field), s,
|
||||
toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result])
|
||||
result = ("{kind: 3, offset: \"$1\", len: $3, " &
|
||||
"typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
|
||||
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
|
||||
else: internalError(n.info, "genObjectFields")
|
||||
|
||||
proc genObjectInfo(p: PProc, typ: PType, name: PRope) =
|
||||
var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n", [name, toRope(ord(typ.kind))])
|
||||
|
||||
proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
|
||||
var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n") % [name, rope(ord(typ.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[toRope(typ.id), genObjectFields(p, typ, typ.n)])
|
||||
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
|
||||
if (typ.kind == tyObject) and (typ.sons[0] != nil):
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
addf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[rope(typ.id), genObjectFields(p, typ, typ.n)])
|
||||
addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
|
||||
if (typ.kind == tyObject) and (typ.sons[0] != nil):
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
|
||||
proc genTupleFields(p: PProc, typ: PType): PRope =
|
||||
var s: PRope = nil
|
||||
proc genTupleFields(p: PProc, typ: PType): Rope =
|
||||
var s: Rope = nil
|
||||
for i in 0 .. <typ.len:
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
s.appf("{kind: 1, offset: \"Field$1\", len: 0, " &
|
||||
if i > 0: add(s, ", " & tnl)
|
||||
s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
|
||||
"typ: $2, name: \"Field$1\", sons: null}",
|
||||
[i.toRope, genTypeInfo(p, typ.sons[i])])
|
||||
result = ropef("{kind: 2, len: $1, offset: 0, " &
|
||||
"typ: null, name: null, sons: [$2]}", [toRope(typ.len), s])
|
||||
[i.rope, genTypeInfo(p, typ.sons[i])])
|
||||
result = ("{kind: 2, len: $1, offset: 0, " &
|
||||
"typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
|
||||
|
||||
proc genTupleInfo(p: PProc, typ: PType, name: PRope) =
|
||||
var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n", [name, toRope(ord(typ.kind))])
|
||||
proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
|
||||
var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n") % [name, rope(ord(typ.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[toRope(typ.id), genTupleFields(p, typ)])
|
||||
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
|
||||
addf(p.g.typeInfo, "var NNI$1 = $2;$n",
|
||||
[rope(typ.id), genTupleFields(p, typ)])
|
||||
addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
|
||||
|
||||
proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
|
||||
proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
|
||||
let length = sonsLen(typ.n)
|
||||
var s: PRope = nil
|
||||
for i in countup(0, length - 1):
|
||||
var s: Rope = nil
|
||||
for i in countup(0, length - 1):
|
||||
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
|
||||
let field = typ.n.sons[i].sym
|
||||
if i > 0: app(s, ", " & tnl)
|
||||
if i > 0: add(s, ", " & tnl)
|
||||
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
|
||||
appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
|
||||
[toRope(field.position), name, makeJSString(extName)])
|
||||
var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
|
||||
"name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s])
|
||||
s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n", [name, toRope(ord(typ.kind))])
|
||||
addf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
|
||||
[rope(field.position), name, makeJSString(extName)])
|
||||
var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
|
||||
"name: null, len: $2, sons: [$3]};$n") % [rope(typ.id), rope(length), s]
|
||||
s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
|
||||
"finalizer: null};$n") % [name, rope(ord(typ.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
app(p.g.typeInfo, n)
|
||||
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
|
||||
add(p.g.typeInfo, n)
|
||||
addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
|
||||
if typ.sons[0] != nil:
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
|
||||
proc genTypeInfo(p: PProc, typ: PType): PRope =
|
||||
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||
var t = typ
|
||||
if t.kind == tyGenericInst: t = lastSon(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||
result = "NTI$1" % [rope(t.id)]
|
||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||
case t.kind
|
||||
of tyDistinct:
|
||||
of tyDistinct:
|
||||
result = genTypeInfo(p, typ.sons[0])
|
||||
of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
|
||||
var s = ropef(
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
|
||||
[result, toRope(ord(t.kind))])
|
||||
var s =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
|
||||
var s = ropef(
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
|
||||
[result, toRope(ord(t.kind))])
|
||||
of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
|
||||
var s =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.lastSon)])
|
||||
of tyArrayConstr, tyArray:
|
||||
var s = ropef(
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
|
||||
[result, toRope(ord(t.kind))])
|
||||
of tyArrayConstr, tyArray:
|
||||
var s =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
appf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.sons[1])])
|
||||
of tyEnum: genEnumInfo(p, t, result)
|
||||
of tyObject: genObjectInfo(p, t, result)
|
||||
|
||||
@@ -9,92 +9,92 @@
|
||||
|
||||
# This include file implements lambda lifting for the transformator.
|
||||
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, magicsys, rodread, lowerings
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
that the calling chain needs to be explicitly modelled. Things to consider:
|
||||
|
||||
|
||||
proc a =
|
||||
var v = 0
|
||||
proc b =
|
||||
var w = 2
|
||||
|
||||
|
||||
for x in 0..3:
|
||||
proc c = capture v, w, x
|
||||
c()
|
||||
b()
|
||||
|
||||
|
||||
for x in 0..4:
|
||||
proc d = capture x
|
||||
d()
|
||||
|
||||
|
||||
Needs to be translated into:
|
||||
|
||||
|
||||
proc a =
|
||||
var cl: *
|
||||
new cl
|
||||
cl.v = 0
|
||||
|
||||
|
||||
proc b(cl) =
|
||||
var bcl: *
|
||||
new bcl
|
||||
bcl.w = 2
|
||||
bcl.up = cl
|
||||
|
||||
|
||||
for x in 0..3:
|
||||
var bcl2: *
|
||||
new bcl2
|
||||
bcl2.up = bcl
|
||||
bcl2.up2 = cl
|
||||
bcl2.x = x
|
||||
|
||||
|
||||
proc c(cl) = capture cl.up2.v, cl.up.w, cl.x
|
||||
c(bcl2)
|
||||
|
||||
|
||||
c(bcl)
|
||||
|
||||
|
||||
b(cl)
|
||||
|
||||
|
||||
for x in 0..4:
|
||||
var acl2: *
|
||||
new acl2
|
||||
acl2.x = x
|
||||
proc d(cl) = capture cl.x
|
||||
d(acl2)
|
||||
|
||||
|
||||
Closures as interfaces:
|
||||
|
||||
|
||||
proc outer: T =
|
||||
var captureMe: TObject # value type required for efficiency
|
||||
proc getter(): int = result = captureMe.x
|
||||
proc setter(x: int) = captureMe.x = x
|
||||
|
||||
|
||||
result = (getter, setter)
|
||||
|
||||
|
||||
Is translated to:
|
||||
|
||||
|
||||
proc outer: T =
|
||||
var cl: *
|
||||
new cl
|
||||
|
||||
|
||||
proc getter(cl): int = result = cl.captureMe.x
|
||||
proc setter(cl: *, x: int) = cl.captureMe.x = x
|
||||
|
||||
|
||||
result = ((cl, getter), (cl, setter))
|
||||
|
||||
|
||||
|
||||
|
||||
For 'byref' capture, the outer proc needs to access the captured var through
|
||||
the indirection too. For 'bycopy' capture, the outer proc accesses the var
|
||||
not through the indirection.
|
||||
|
||||
Possible optimizations:
|
||||
|
||||
|
||||
Possible optimizations:
|
||||
|
||||
1) If the closure contains a single 'ref' and this
|
||||
reference is not re-assigned (check ``sfAddrTaken`` flag) make this the
|
||||
closure. This is an important optimization if closures are used as
|
||||
closure. This is an important optimization if closures are used as
|
||||
interfaces.
|
||||
2) If the closure does not escape, put it onto the stack, not on the heap.
|
||||
3) Dataflow analysis would help to eliminate the 'up' indirections.
|
||||
@@ -126,7 +126,7 @@ type
|
||||
fn, closureParam, state, resultSym: PSym # most are only valid if
|
||||
# fn.kind == skClosureIterator
|
||||
obj: PType
|
||||
|
||||
|
||||
PEnv = ref TEnv
|
||||
TEnv {.final.} = object of RootObj
|
||||
attachedNode, replacementNode: PNode
|
||||
@@ -141,7 +141,7 @@ type
|
||||
# if up.fn != fn then we cross function boundaries.
|
||||
# This is an important case to consider.
|
||||
vars: IntSet # variables belonging to this environment
|
||||
|
||||
|
||||
TOuterContext = object
|
||||
fn: PSym # may also be a module!
|
||||
head: PEnv
|
||||
@@ -284,7 +284,7 @@ proc addClosureParam(fn: PSym; e: PEnv) =
|
||||
#assert e.obj.kind == tyObject
|
||||
|
||||
proc illegalCapture(s: PSym): bool {.inline.} =
|
||||
result = skipTypes(s.typ, abstractInst).kind in
|
||||
result = skipTypes(s.typ, abstractInst).kind in
|
||||
{tyVar, tyOpenArray, tyVarargs} or
|
||||
s.kind == skResult
|
||||
|
||||
@@ -344,7 +344,7 @@ proc createUpField(obj, fieldType: PType): PSym =
|
||||
#rawAddField(obj, result)
|
||||
addField(obj, result)
|
||||
|
||||
proc captureVar(o: POuterContext; top: PEnv; local: PSym;
|
||||
proc captureVar(o: POuterContext; top: PEnv; local: PSym;
|
||||
info: TLineInfo): bool =
|
||||
# first check if we should be concerned at all:
|
||||
var it = top
|
||||
@@ -408,7 +408,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
|
||||
var s = n.sym
|
||||
if interestingVar(s) and e.fn != s.owner:
|
||||
if captureVar(o, e, s, n.info): result = 1
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
|
||||
nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection:
|
||||
discard
|
||||
else:
|
||||
@@ -418,7 +418,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
|
||||
proc generateThunk(prc: PNode, dest: PType): PNode =
|
||||
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
|
||||
## a closure.
|
||||
|
||||
|
||||
# we cannot generate a proper thunk here for GC-safety reasons (see internal
|
||||
# documentation):
|
||||
if gCmd == cmdCompileToJS: return prc
|
||||
@@ -515,7 +515,7 @@ proc closureCreationPoint(n: PNode): PNode =
|
||||
|
||||
proc addParamsToEnv(fn: PSym; env: PEnv) =
|
||||
let params = fn.typ.n
|
||||
for i in 1.. <params.len:
|
||||
for i in 1.. <params.len:
|
||||
if params.sons[i].kind != nkSym:
|
||||
internalError(params.info, "liftLambdas: strange params")
|
||||
let param = params.sons[i].sym
|
||||
@@ -541,7 +541,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
addParamsToEnv(fn, envB)
|
||||
searchForInnerProcs(o, body, envB)
|
||||
fn.ast.sons[bodyPos] = ex
|
||||
|
||||
|
||||
let capturedCounter = gatherVars(o, envB, body)
|
||||
# dummy closure param needed?
|
||||
if capturedCounter == 0 and fn.typ.callConv == ccClosure:
|
||||
@@ -560,7 +560,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
|
||||
# some nodes open a new scope, so they are candidates for the insertion
|
||||
# of closure creation; however for simplicity we merge closures between
|
||||
# branches, in fact, only loop bodies are of interest here as only they
|
||||
# branches, in fact, only loop bodies are of interest here as only they
|
||||
# yield observable changes in semantics. For Zahary we also
|
||||
# include ``nkBlock``. We don't do this for closure iterators because
|
||||
# 'yield' can produce wrong code otherwise (XXX show example):
|
||||
@@ -598,7 +598,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
internalError(it.info, "searchForInnerProcs")
|
||||
of nkClosure:
|
||||
searchForInnerProcs(o, n.sons[0], env)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkTypeSection:
|
||||
# don't recurse here:
|
||||
discard
|
||||
@@ -606,7 +606,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
searchForInnerProcs(o, n.sons[i], env)
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
|
||||
# mean to be able to capture string literals which have no GC header.
|
||||
# However this can only happen if the capture happens through a parameter,
|
||||
@@ -624,7 +624,7 @@ proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PNode): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env))
|
||||
|
||||
|
||||
# add assignment statements:
|
||||
for local in scope.capturedVars:
|
||||
let fieldAccess = indirectAccess(env, local, env.info)
|
||||
@@ -696,10 +696,10 @@ proc transformYield(c: POuterContext, n: PNode, it: TIter): PNode =
|
||||
retStmt.add(a)
|
||||
else:
|
||||
retStmt.add(emptyNode)
|
||||
|
||||
|
||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(retStmt)
|
||||
@@ -725,7 +725,7 @@ proc liftIterSym(n: PNode; owner: PSym): PNode =
|
||||
assert iter.kind == skClosureIterator
|
||||
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
|
||||
let hp = getHiddenParam(iter)
|
||||
let env = newSym(skLet, iter.name, owner, n.info)
|
||||
env.typ = hp.typ
|
||||
@@ -800,7 +800,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
# with some rather primitive check for now:
|
||||
if n.kind == nkStmtList and n.len > 0:
|
||||
if n.sons[0].kind == nkGotoState: return nil
|
||||
if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
|
||||
if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
|
||||
n[1][0].kind == nkGotoState:
|
||||
return nil
|
||||
result = newNodeI(nkStmtList, it.fn.info)
|
||||
@@ -812,7 +812,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
var state0 = newNodeI(nkState, it.fn.info)
|
||||
state0.add(newIntNode(nkIntLit, 0))
|
||||
result.add(state0)
|
||||
|
||||
|
||||
let newBody = transformOuterProc(o, n, it)
|
||||
if newBody != nil:
|
||||
result.add(newBody)
|
||||
@@ -899,7 +899,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
let x = closure.createdVar
|
||||
assert x != nil
|
||||
return makeClosure(local, x, n.info)
|
||||
|
||||
|
||||
if not contains(o.capturedVars, local.id): return
|
||||
# change 'local' to 'closure.local', unless it's a 'byCopy' variable:
|
||||
# if sfByCopy notin local.flags:
|
||||
@@ -946,7 +946,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS or
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS or
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
@@ -985,17 +985,17 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||
|
||||
proc liftForLoop*(body: PNode): PNode =
|
||||
# problem ahead: the iterator could be invoked indirectly, but then
|
||||
# we don't know what environment to create here:
|
||||
#
|
||||
# we don't know what environment to create here:
|
||||
#
|
||||
# iterator count(): int =
|
||||
# yield 0
|
||||
#
|
||||
#
|
||||
# iterator count2(): int =
|
||||
# var x = 3
|
||||
# yield x
|
||||
# inc x
|
||||
# yield x
|
||||
#
|
||||
#
|
||||
# proc invoke(iter: iterator(): int) =
|
||||
# for x in iter(): echo x
|
||||
#
|
||||
@@ -1004,7 +1004,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
for i in foo(): ...
|
||||
|
||||
Is transformed to:
|
||||
|
||||
|
||||
cl = createClosure()
|
||||
while true:
|
||||
let i = foo(cl)
|
||||
@@ -1016,7 +1016,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
var call = body[L-2]
|
||||
|
||||
result = newNodeI(nkStmtList, body.info)
|
||||
|
||||
|
||||
# static binding?
|
||||
var env: PSym
|
||||
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
|
||||
@@ -1030,18 +1030,18 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env.newSymNode))
|
||||
|
||||
|
||||
var loopBody = newNodeI(nkStmtList, body.info, 3)
|
||||
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
|
||||
whileLoop.sons[1] = loopBody
|
||||
result.add whileLoop
|
||||
|
||||
|
||||
# setup loopBody:
|
||||
# gather vars in a tuple:
|
||||
var v2 = newNodeI(nkLetSection, body.info)
|
||||
var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
|
||||
for i in 0 .. L-3:
|
||||
for i in 0 .. L-3:
|
||||
assert body[i].kind == nkSym
|
||||
body[i].sym.kind = skLet
|
||||
addSon(vpart, body[i])
|
||||
|
||||
@@ -131,24 +131,10 @@ type
|
||||
|
||||
var gLinesCompiled*: int # all lines that have been compiled
|
||||
|
||||
proc isKeyword*(kind: TTokType): bool
|
||||
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken)
|
||||
# reads in the next token into tok and skips it
|
||||
|
||||
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
|
||||
newLineInfo(L.fileIdx, tok.line, tok.col)
|
||||
|
||||
proc closeLexer*(lex: var TLexer)
|
||||
proc printTok*(tok: TToken)
|
||||
proc tokToStr*(tok: TToken): string
|
||||
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
openLexer(lex, filename.fileInfoIdx, inputstream)
|
||||
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
|
||||
|
||||
proc isKeyword(kind: TTokType): bool =
|
||||
proc isKeyword*(kind: TTokType): bool =
|
||||
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
|
||||
|
||||
proc isNimIdentifier*(s: string): bool =
|
||||
@@ -206,14 +192,17 @@ proc fillToken(L: var TToken) =
|
||||
L.base = base10
|
||||
L.ident = dummyIdent
|
||||
|
||||
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
|
||||
proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
|
||||
openBaseLexer(lex, inputstream)
|
||||
lex.fileIdx = fileidx
|
||||
lex.indentAhead = - 1
|
||||
lex.currLineIndent = 0
|
||||
inc(lex.lineNumber, inputstream.lineOffset)
|
||||
|
||||
proc closeLexer(lex: var TLexer) =
|
||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||
openLexer(lex, filename.fileInfoIdx, inputstream)
|
||||
|
||||
proc closeLexer*(lex: var TLexer) =
|
||||
inc(gLinesCompiled, lex.lineNumber)
|
||||
closeBaseLexer(lex)
|
||||
|
||||
@@ -229,7 +218,7 @@ proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
else:
|
||||
L.errorHandler(info, msg, arg)
|
||||
|
||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
L.dispMessage(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
@@ -785,7 +774,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
break # EndOfFile also leaves the loop
|
||||
L.bufpos = pos
|
||||
|
||||
proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||
fillToken(tok)
|
||||
if L.indentAhead >= 0:
|
||||
tok.indent = L.indentAhead
|
||||
|
||||
@@ -382,11 +382,11 @@ proc getRoot*(n: PNode): PSym =
|
||||
if getMagic(n) == mSlice: result = getRoot(n.sons[1])
|
||||
else: discard
|
||||
|
||||
proc newIntLit(value: BiggestInt): PNode =
|
||||
proc newIntLit*(value: BiggestInt): PNode =
|
||||
result = nkIntLit.newIntNode(value)
|
||||
result.typ = getSysType(tyInt)
|
||||
|
||||
proc genHigh(n: PNode): PNode =
|
||||
proc genHigh*(n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}:
|
||||
result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
|
||||
else:
|
||||
|
||||
@@ -54,6 +54,7 @@ proc commandDoc2 =
|
||||
finishDoc2Pass(gProjectName)
|
||||
|
||||
proc commandCompileToC =
|
||||
extccomp.initVars()
|
||||
semanticPasses()
|
||||
registerPass(cgenPass)
|
||||
rodPass()
|
||||
|
||||
@@ -387,7 +387,7 @@ const
|
||||
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
||||
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
||||
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
||||
warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized [Uninit]",
|
||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
|
||||
@@ -449,10 +449,10 @@ type
|
||||
fullPath: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: PRope # cached quoted short name for codegen
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
# purposes
|
||||
|
||||
lines*: seq[PRope] # the source code of the module
|
||||
lines*: seq[Rope] # the source code of the module
|
||||
# used for better error messages and
|
||||
# embedding the original source in the
|
||||
# generated code
|
||||
@@ -493,24 +493,20 @@ proc toCChar*(c: char): string =
|
||||
of '\'', '\"', '\\': result = '\\' & c
|
||||
else: result = $(c)
|
||||
|
||||
proc makeCString*(s: string): PRope =
|
||||
# BUGFIX: We have to split long strings into many ropes. Otherwise
|
||||
# this could trigger an internalError(). See the ropes module for
|
||||
# further information.
|
||||
proc makeCString*(s: string): Rope =
|
||||
const
|
||||
MaxLineLength = 64
|
||||
result = nil
|
||||
var res = "\""
|
||||
var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
|
||||
add(res, "\"")
|
||||
for i in countup(0, len(s) - 1):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
add(res, '\"')
|
||||
add(res, tnl)
|
||||
app(result, toRope(res)) # reset:
|
||||
setLen(res, 1)
|
||||
res[0] = '\"'
|
||||
add(res, '\"')
|
||||
add(res, toCChar(s[i]))
|
||||
add(res, '\"')
|
||||
app(result, toRope(res))
|
||||
add(result, rope(res))
|
||||
|
||||
|
||||
proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
@@ -568,7 +564,7 @@ var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
proc sourceLine*(i: TLineInfo): PRope
|
||||
proc sourceLine*(i: TLineInfo): Rope
|
||||
|
||||
var
|
||||
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
|
||||
@@ -776,7 +772,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
|
||||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
msgWriteln(indent & $info.sourceLine)
|
||||
msgWriteln(indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
@@ -831,6 +827,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc localError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doNothing)
|
||||
|
||||
proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
|
||||
localError(info, format % params)
|
||||
|
||||
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
@@ -852,9 +851,9 @@ template internalAssert*(e: bool): stmt =
|
||||
if not e: internalError($instantiationInfo())
|
||||
|
||||
proc addSourceLine*(fileIdx: int32, line: string) =
|
||||
fileInfos[fileIdx].lines.add line.toRope
|
||||
fileInfos[fileIdx].lines.add line.rope
|
||||
|
||||
proc sourceLine*(i: TLineInfo): PRope =
|
||||
proc sourceLine*(i: TLineInfo): Rope =
|
||||
if i.fileIndex < 0: return nil
|
||||
|
||||
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
|
||||
@@ -869,16 +868,14 @@ proc sourceLine*(i: TLineInfo): PRope =
|
||||
|
||||
result = fileInfos[i.fileIndex].lines[i.line-1]
|
||||
|
||||
proc quotedFilename*(i: TLineInfo): PRope =
|
||||
proc quotedFilename*(i: TLineInfo): Rope =
|
||||
internalAssert i.fileIndex >= 0
|
||||
result = fileInfos[i.fileIndex].quotedName
|
||||
|
||||
ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
|
||||
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
||||
case err
|
||||
of rInvalidFormatStr:
|
||||
internalError("ropes: invalid format string: " & msg)
|
||||
of rTokenTooLong:
|
||||
internalError("ropes: token too long: " & msg)
|
||||
of rCannotOpenFile:
|
||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||
|
||||
|
||||
@@ -190,6 +190,8 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||
result = arLocalLValue
|
||||
else:
|
||||
result = arLValue
|
||||
elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
|
||||
result = arLValue
|
||||
elif n.sym.kind == skType:
|
||||
let t = n.sym.typ.skipTypes({tyTypeDesc})
|
||||
if t.kind == tyVar: result = arStrange
|
||||
|
||||
@@ -212,27 +212,29 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
let relevantChar = tok.ident.s[0]
|
||||
|
||||
# arrow like?
|
||||
if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
|
||||
if L > 1 and tok.ident.s[L-1] == '>' and
|
||||
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
|
||||
|
||||
template considerAsgn(value: expr) =
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: value
|
||||
|
||||
case relevantChar
|
||||
of '$', '^': considerAsgn(10)
|
||||
of '*', '%', '/', '\\': considerAsgn(9)
|
||||
of '~': result = considerStrongSpaces(8)
|
||||
of '~': result = 8
|
||||
of '+', '-', '|': considerAsgn(8)
|
||||
of '&': considerAsgn(7)
|
||||
of '=', '<', '>', '!': result = considerStrongSpaces(5)
|
||||
of '=', '<', '>', '!': result = 5
|
||||
of '.': considerAsgn(6)
|
||||
of '?': result = considerStrongSpaces(2)
|
||||
of '?': result = 2
|
||||
else: considerAsgn(2)
|
||||
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
||||
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
|
||||
of tkDotDot: result = considerStrongSpaces(6)
|
||||
of tkDotDot: result = 6
|
||||
of tkAnd: result = 4
|
||||
of tkOr, tkXor, tkPtr, tkRef: result = 3
|
||||
else: result = -10
|
||||
else: return -10
|
||||
result = considerStrongSpaces(result)
|
||||
|
||||
proc isOperator(tok: TToken): bool =
|
||||
## Determines if the given token is an operator type token.
|
||||
@@ -387,7 +389,6 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
eat(p, endTok)
|
||||
|
||||
proc dotExpr(p: var TParser, a: PNode): PNode =
|
||||
#| dotExpr = expr '.' optInd symbol
|
||||
@@ -943,8 +944,7 @@ proc parseDoBlock(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
let params = parseParamList(p, retColon=false)
|
||||
let pragmas = optPragmas(p)
|
||||
eat(p, tkColon)
|
||||
skipComment(p, result)
|
||||
colcom(p, result)
|
||||
result = newProcNode(nkDo, info, parseStmt(p),
|
||||
params = params,
|
||||
pragmas = pragmas)
|
||||
@@ -1138,9 +1138,11 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||
result = makeCall(result)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
let stmtList = newNodeP(nkStmtList, p)
|
||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, makeStmtList(body))
|
||||
stmtList.add body
|
||||
#addSon(result, makeStmtList(body))
|
||||
while sameInd(p):
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
@@ -1152,19 +1154,22 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
eat(p, tkColon)
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
skipComment(p, b)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
else: break
|
||||
eat(p, tkColon)
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
addSon(stmtList, b)
|
||||
if b.kind == nkElse: break
|
||||
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
|
||||
# to keep backwards compatibility (see tests/vm/tstringnil)
|
||||
result.add stmtList[0]
|
||||
else:
|
||||
result.add stmtList
|
||||
|
||||
proc parseExprStmt(p: var TParser): PNode =
|
||||
#| exprStmt = simpleExpr
|
||||
@@ -1309,8 +1314,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
||||
var branch = newNodeP(nkElifBranch, p)
|
||||
optInd(p, branch)
|
||||
addSon(branch, parseExpr(p))
|
||||
eat(p, tkColon)
|
||||
skipComment(p, branch)
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseStmt(p))
|
||||
skipComment(p, branch)
|
||||
addSon(result, branch)
|
||||
@@ -1318,8 +1322,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
||||
if p.tok.tokType == tkElse and sameOrNoInd(p):
|
||||
var branch = newNodeP(nkElse, p)
|
||||
eat(p, tkElse)
|
||||
eat(p, tkColon)
|
||||
skipComment(p, branch)
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseStmt(p))
|
||||
addSon(result, branch)
|
||||
|
||||
@@ -1367,13 +1370,11 @@ proc parseCase(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
eat(p, tkColon)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
else: break
|
||||
skipComment(p, b)
|
||||
colcom(p, b)
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkElse: break
|
||||
@@ -1390,8 +1391,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
|
||||
#| (optInd 'finally' colcom stmt)?
|
||||
result = newNodeP(nkTryStmt, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
skipComment(p, result)
|
||||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
var b: PNode = nil
|
||||
while sameOrNoInd(p) or isExpr:
|
||||
@@ -1401,10 +1401,9 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
|
||||
exprList(p, tkColon, b)
|
||||
of tkFinally:
|
||||
b = newNodeP(nkFinally, p)
|
||||
getTokNoInd(p)
|
||||
eat(p, tkColon)
|
||||
getTok(p)
|
||||
else: break
|
||||
skipComment(p, b)
|
||||
colcom(p, b)
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(result, b)
|
||||
if b.kind == nkFinally: break
|
||||
@@ -1413,7 +1412,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
|
||||
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| exceptBlock = 'except' colcom stmt
|
||||
result = newNodeP(kind, p)
|
||||
getTokNoInd(p)
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
@@ -1446,7 +1445,7 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
|
||||
#| staticStmt = 'static' colcom stmt
|
||||
#| deferStmt = 'defer' colcom stmt
|
||||
result = newNodeP(k, p)
|
||||
getTokNoInd(p)
|
||||
getTok(p)
|
||||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
@@ -1685,9 +1684,8 @@ proc parseObjectCase(p: var TParser): PNode =
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
eat(p, tkColon)
|
||||
else: break
|
||||
skipComment(p, b)
|
||||
colcom(p, b)
|
||||
var fields = parseObjectPart(p)
|
||||
if fields.kind == nkEmpty:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
@@ -2030,8 +2028,8 @@ proc parseString*(s: string; filename: string = ""; line: int = 0;
|
||||
var parser: TParser
|
||||
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
||||
# spaces...
|
||||
openParser(parser, filename, stream, false)
|
||||
parser.lex.errorHandler = errorHandler
|
||||
openParser(parser, filename, stream, false)
|
||||
|
||||
result = parser.parseAll
|
||||
closeParser(parser)
|
||||
|
||||
43
compiler/plugins.nim
Normal file
43
compiler/plugins.nim
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Plugin support for the Nim compiler. Right now there are no plugins and they
|
||||
## need to be build with the compiler, no DLL support.
|
||||
|
||||
import ast, semdata, idents
|
||||
|
||||
type
|
||||
Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
|
||||
Plugin = ref object
|
||||
fn, module, package: PIdent
|
||||
t: Transformation
|
||||
next: Plugin
|
||||
|
||||
proc pluginMatches(p: Plugin; s: PSym): bool =
|
||||
if s.name.id != p.fn.id: return false
|
||||
let module = s.owner
|
||||
if module == nil or module.kind != skModule or
|
||||
module.name.id != p.module.id: return false
|
||||
let package = module.owner
|
||||
if package == nil or package.kind != skPackage or
|
||||
package.name.id != p.package.id: return false
|
||||
return true
|
||||
|
||||
var head: Plugin
|
||||
|
||||
proc getPlugin*(fn: PSym): Transformation =
|
||||
var it = head
|
||||
while it != nil:
|
||||
if pluginMatches(it, fn): return it.t
|
||||
it = it.next
|
||||
|
||||
proc registerPlugin*(package, module, fn: string; t: Transformation) =
|
||||
let oldHead = head
|
||||
head = Plugin(fn: getIdent(fn), module: getIdent(module),
|
||||
package: getIdent(package), t: t, next: oldHead)
|
||||
@@ -60,7 +60,7 @@ const
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard}
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||
letPragmas* = varPragmas
|
||||
@@ -89,7 +89,7 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
invalidPragma(it)
|
||||
|
||||
proc setExternName(s: PSym, extname: string) =
|
||||
s.loc.r = toRope(extname % s.name.s)
|
||||
s.loc.r = rope(extname % s.name.s)
|
||||
if gCmd == cmdPretty and '$' notin extname:
|
||||
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
||||
s.loc.flags.incl(lfFullExternalName)
|
||||
@@ -105,7 +105,7 @@ proc validateExternCName(s: PSym, info: TLineInfo) =
|
||||
## Valid identifiers are those alphanumeric including the underscore not
|
||||
## starting with a number. If the check fails, a generic error will be
|
||||
## displayed to the user.
|
||||
let target = ropeToStr(s.loc.r)
|
||||
let target = $s.loc.r
|
||||
if target.len < 1 or target[0] notin IdentStartChars or
|
||||
not target.allCharsInSet(IdentChars):
|
||||
localError(info, errGenerated, "invalid exported symbol")
|
||||
@@ -677,7 +677,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
incl(sym.loc.flags, lfHeader)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
|
||||
of wDestructor:
|
||||
sym.flags.incl sfOverriden
|
||||
if sym.name.s.normalize != "destroy":
|
||||
@@ -843,6 +843,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||
of wGoto:
|
||||
if sym == nil or sym.kind notin {skVar, skLet}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.flags.incl sfGoto
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
@@ -865,9 +870,11 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
while it != nil:
|
||||
let o = it.otherPragmas
|
||||
if not o.isNil:
|
||||
pushInfoContext(n.info)
|
||||
for i in countup(0, sonsLen(o) - 1):
|
||||
if singlePragma(c, sym, o, i, validPragmas):
|
||||
internalError(n.info, "implicitPragmas")
|
||||
popInfoContext()
|
||||
it = it.next.POptionEntry
|
||||
|
||||
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
|
||||
@@ -877,7 +884,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
sfImportc in sym.flags and lib != nil:
|
||||
incl(sym.loc.flags, lfDynamicLib)
|
||||
addToLib(lib, sym)
|
||||
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
|
||||
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
|
||||
|
||||
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
||||
if n == nil or n.sons == nil:
|
||||
|
||||
@@ -503,6 +503,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
|
||||
|
||||
proc hasCom(n: PNode): bool =
|
||||
result = false
|
||||
if n.isNil: return false
|
||||
if n.comment != nil: return true
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: discard
|
||||
|
||||
@@ -277,7 +277,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
|
||||
loc.t = nil
|
||||
if r.s[r.pos] == '!':
|
||||
inc(r.pos)
|
||||
loc.r = toRope(decodeStr(r.s, r.pos))
|
||||
loc.r = rope(decodeStr(r.s, r.pos))
|
||||
else:
|
||||
loc.r = nil
|
||||
if r.s[r.pos] == '>': inc(r.pos)
|
||||
@@ -344,7 +344,7 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
|
||||
result.kind = TLibKind(decodeVInt(r.s, r.pos))
|
||||
if r.s[r.pos] != '|': internalError("decodeLib: 1")
|
||||
inc(r.pos)
|
||||
result.name = toRope(decodeStr(r.s, r.pos))
|
||||
result.name = rope(decodeStr(r.s, r.pos))
|
||||
if r.s[r.pos] != '|': internalError("decodeLib: 2")
|
||||
inc(r.pos)
|
||||
result.path = decodeNode(r, info)
|
||||
|
||||
@@ -186,7 +186,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
pushType(w, loc.t)
|
||||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr(ropeToStr(loc.r), result)
|
||||
encodeStr($loc.r, result)
|
||||
if oldLen + 1 == result.len:
|
||||
# no data was necessary, so remove the '<' again:
|
||||
setLen(result, oldLen)
|
||||
@@ -241,7 +241,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
encodeStr(ropeToStr(lib.name), result)
|
||||
encodeStr($lib.name, result)
|
||||
add(result, '|')
|
||||
encodeNode(w, info, lib.path, result)
|
||||
|
||||
|
||||
@@ -56,77 +56,59 @@
|
||||
# To cache them they are inserted in a `cache` array.
|
||||
|
||||
import
|
||||
strutils, platform, hashes, crc, options
|
||||
platform, hashes
|
||||
|
||||
type
|
||||
TFormatStr* = string # later we may change it to CString for better
|
||||
FormatStr* = string # later we may change it to CString for better
|
||||
# performance of the code generator (assignments
|
||||
# copy the format strings
|
||||
# though it is not necessary)
|
||||
PRope* = ref TRope
|
||||
TRope*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||
# by nil to safe space
|
||||
left*, right*: PRope
|
||||
Rope* = ref RopeObj
|
||||
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||
# by nil to safe space
|
||||
left*, right*: Rope
|
||||
length*: int
|
||||
data*: string # != nil if a leaf
|
||||
|
||||
TRopeSeq* = seq[PRope]
|
||||
RopeSeq* = seq[Rope]
|
||||
|
||||
TRopesError* = enum
|
||||
RopesError* = enum
|
||||
rCannotOpenFile
|
||||
rInvalidFormatStr
|
||||
rTokenTooLong
|
||||
|
||||
proc con*(a, b: PRope): PRope
|
||||
proc con*(a: PRope, b: string): PRope
|
||||
proc con*(a: string, b: PRope): PRope
|
||||
proc con*(a: varargs[PRope]): PRope
|
||||
proc app*(a: var PRope, b: PRope)
|
||||
proc app*(a: var PRope, b: string)
|
||||
proc prepend*(a: var PRope, b: PRope)
|
||||
proc toRope*(s: string): PRope
|
||||
proc toRope*(i: BiggestInt): PRope
|
||||
proc ropeLen*(a: PRope): int
|
||||
proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
|
||||
proc ropeToStr*(p: PRope): string
|
||||
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
|
||||
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
|
||||
proc ropeEqualsFile*(r: PRope, f: string): bool
|
||||
# returns true if the rope r is the same as the contents of file f
|
||||
proc ropeInvariant*(r: PRope): bool
|
||||
# exported for debugging
|
||||
# implementation
|
||||
|
||||
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
|
||||
var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
|
||||
# avoid dependency on msgs.nim
|
||||
|
||||
proc ropeLen(a: PRope): int =
|
||||
proc len*(a: Rope): int =
|
||||
## the rope's length
|
||||
if a == nil: result = 0
|
||||
else: result = a.length
|
||||
|
||||
proc newRope*(data: string = nil): PRope =
|
||||
proc newRope(data: string = nil): Rope =
|
||||
new(result)
|
||||
if data != nil:
|
||||
result.length = len(data)
|
||||
result.data = data
|
||||
|
||||
proc newMutableRope*(capacity = 30): PRope =
|
||||
proc newMutableRope*(capacity = 30): Rope =
|
||||
## creates a new rope that supports direct modifications of the rope's
|
||||
## 'data' and 'length' fields.
|
||||
new(result)
|
||||
result.data = newStringOfCap(capacity)
|
||||
|
||||
proc freezeMutableRope*(r: PRope) {.inline.} =
|
||||
proc freezeMutableRope*(r: Rope) {.inline.} =
|
||||
r.length = r.data.len
|
||||
|
||||
var
|
||||
cache: array[0..2048*2 - 1, PRope]
|
||||
cache: array[0..2048*2 - 1, Rope]
|
||||
|
||||
proc resetRopeCache* =
|
||||
for i in low(cache)..high(cache):
|
||||
cache[i] = nil
|
||||
|
||||
proc ropeInvariant(r: PRope): bool =
|
||||
proc ropeInvariant(r: Rope): bool =
|
||||
if r == nil:
|
||||
result = true
|
||||
else:
|
||||
@@ -143,7 +125,7 @@ var gCacheTries* = 0
|
||||
var gCacheMisses* = 0
|
||||
var gCacheIntTries* = 0
|
||||
|
||||
proc insertInCache(s: string): PRope =
|
||||
proc insertInCache(s: string): Rope =
|
||||
inc gCacheTries
|
||||
var h = hash(s) and high(cache)
|
||||
result = cache[h]
|
||||
@@ -152,82 +134,77 @@ proc insertInCache(s: string): PRope =
|
||||
result = newRope(s)
|
||||
cache[h] = result
|
||||
|
||||
proc toRope(s: string): PRope =
|
||||
proc rope*(s: string): Rope =
|
||||
## Converts a string to a rope.
|
||||
if s.len == 0:
|
||||
result = nil
|
||||
else:
|
||||
result = insertInCache(s)
|
||||
assert(ropeInvariant(result))
|
||||
|
||||
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
|
||||
var length = len(rs)
|
||||
if at > length:
|
||||
setLen(rs, at + 1)
|
||||
else:
|
||||
setLen(rs, length + 1) # move old rope elements:
|
||||
for i in countdown(length, at + 1):
|
||||
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
|
||||
rs[at] = r
|
||||
proc rope*(i: BiggestInt): Rope =
|
||||
## Converts an int to a rope.
|
||||
inc gCacheIntTries
|
||||
result = rope($i)
|
||||
|
||||
proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
|
||||
var stack = @[r]
|
||||
while len(stack) > 0:
|
||||
var it = pop(stack)
|
||||
while it.data == nil:
|
||||
add(stack, it.right)
|
||||
it = it.left
|
||||
assert(it.data != nil)
|
||||
copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
|
||||
inc(resultLen, it.length)
|
||||
assert(resultLen <= len(result))
|
||||
proc rope*(f: BiggestFloat): Rope =
|
||||
## Converts a float to a rope.
|
||||
result = rope($f)
|
||||
|
||||
proc ropeToStr(p: PRope): string =
|
||||
if p == nil:
|
||||
result = ""
|
||||
else:
|
||||
result = newString(p.length)
|
||||
var resultLen = 0
|
||||
newRecRopeToStr(result, resultLen, p)
|
||||
|
||||
proc con(a, b: PRope): PRope =
|
||||
if a == nil: result = b
|
||||
elif b == nil: result = a
|
||||
proc `&`*(a, b: Rope): Rope =
|
||||
if a == nil:
|
||||
result = b
|
||||
elif b == nil:
|
||||
result = a
|
||||
else:
|
||||
result = newRope()
|
||||
result.length = a.length + b.length
|
||||
result.left = a
|
||||
result.right = b
|
||||
|
||||
proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
|
||||
proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
|
||||
proc `&`*(a: Rope, b: string): Rope =
|
||||
## the concatenation operator for ropes.
|
||||
result = a & rope(b)
|
||||
|
||||
proc con(a: varargs[PRope]): PRope =
|
||||
for i in countup(0, high(a)): result = con(result, a[i])
|
||||
proc `&`*(a: string, b: Rope): Rope =
|
||||
## the concatenation operator for ropes.
|
||||
result = rope(a) & b
|
||||
|
||||
proc ropeConcat*(a: varargs[PRope]): PRope =
|
||||
# not overloaded version of concat to speed-up `rfmt` a little bit
|
||||
for i in countup(0, high(a)): result = con(result, a[i])
|
||||
proc `&`*(a: openArray[Rope]): Rope =
|
||||
## the concatenation operator for an openarray of ropes.
|
||||
for i in countup(0, high(a)): result = result & a[i]
|
||||
|
||||
proc toRope(i: BiggestInt): PRope =
|
||||
inc gCacheIntTries
|
||||
result = toRope($i)
|
||||
proc add*(a: var Rope, b: Rope) =
|
||||
## adds `b` to the rope `a`.
|
||||
a = a & b
|
||||
|
||||
proc app(a: var PRope, b: PRope) = a = con(a, b)
|
||||
proc app(a: var PRope, b: string) = a = con(a, b)
|
||||
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
|
||||
proc add*(a: var Rope, b: string) =
|
||||
## adds `b` to the rope `a`.
|
||||
a = a & b
|
||||
|
||||
proc writeRope*(f: File, c: PRope) =
|
||||
var stack = @[c]
|
||||
while len(stack) > 0:
|
||||
var it = pop(stack)
|
||||
while it.data == nil:
|
||||
add(stack, it.right)
|
||||
it = it.left
|
||||
assert(it != nil)
|
||||
assert(it.data != nil)
|
||||
write(f, it.data)
|
||||
iterator leaves*(r: Rope): string =
|
||||
## iterates over any leaf string in the rope `r`.
|
||||
if r != nil:
|
||||
var stack = @[r]
|
||||
while stack.len > 0:
|
||||
var it = stack.pop
|
||||
while isNil(it.data):
|
||||
stack.add(it.right)
|
||||
it = it.left
|
||||
assert(it != nil)
|
||||
assert(it.data != nil)
|
||||
yield it.data
|
||||
|
||||
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
||||
iterator items*(r: Rope): char =
|
||||
## iterates over any character in the rope `r`.
|
||||
for s in leaves(r):
|
||||
for c in items(s): yield c
|
||||
|
||||
proc writeRope*(f: File, r: Rope) =
|
||||
## writes a rope to a file.
|
||||
for s in leaves(r): write(f, s)
|
||||
|
||||
proc writeRope*(head: Rope, filename: string, useWarning = false) =
|
||||
var f: File
|
||||
if open(f, filename, fmWrite):
|
||||
if head != nil: writeRope(f, head)
|
||||
@@ -235,42 +212,69 @@ proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
||||
else:
|
||||
errorHandler(rCannotOpenFile, filename, useWarning)
|
||||
|
||||
proc `$`*(r: Rope): string =
|
||||
## converts a rope back to a string.
|
||||
result = newString(r.len)
|
||||
setLen(result, 0)
|
||||
for s in leaves(r): add(result, s)
|
||||
|
||||
proc ropeConcat*(a: varargs[Rope]): Rope =
|
||||
# not overloaded version of concat to speed-up `rfmt` a little bit
|
||||
for i in countup(0, high(a)): result = result & a[i]
|
||||
|
||||
proc prepend*(a: var Rope, b: Rope) = a = b & a
|
||||
proc prepend*(a: var Rope, b: string) = a = b & a
|
||||
|
||||
var
|
||||
rnl* = tnl.newRope
|
||||
softRnl* = tnl.newRope
|
||||
|
||||
proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
var i = 0
|
||||
var length = len(frmt)
|
||||
result = nil
|
||||
var num = 0
|
||||
while i <= length - 1:
|
||||
while i < length:
|
||||
if frmt[i] == '$':
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '$':
|
||||
app(result, "$")
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '#':
|
||||
inc(i)
|
||||
app(result, args[num])
|
||||
add(result, args[num])
|
||||
inc(num)
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if frmt[i] notin {'0'..'9'}: break
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
errorHandler(rInvalidFormatStr, $(j))
|
||||
else:
|
||||
app(result, args[j - 1])
|
||||
add(result, args[j-1])
|
||||
of '{':
|
||||
inc(i)
|
||||
var j = 0
|
||||
while frmt[i] in {'0'..'9'}:
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
num = j
|
||||
if frmt[i] == '}': inc(i)
|
||||
else: errorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||
|
||||
if j > high(args) + 1:
|
||||
errorHandler(rInvalidFormatStr, $(j))
|
||||
else:
|
||||
add(result, args[j-1])
|
||||
of 'n':
|
||||
app(result, softRnl)
|
||||
inc i
|
||||
add(result, softRnl)
|
||||
inc(i)
|
||||
of 'N':
|
||||
app(result, rnl)
|
||||
add(result, rnl)
|
||||
inc(i)
|
||||
else:
|
||||
errorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||
@@ -279,83 +283,67 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
app(result, substr(frmt, start, i - 1))
|
||||
add(result, substr(frmt, start, i - 1))
|
||||
assert(ropeInvariant(result))
|
||||
|
||||
proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
|
||||
## shortcut for ``add(c, frmt % args)``.
|
||||
add(c, frmt % args)
|
||||
|
||||
when true:
|
||||
template `~`*(r: string): PRope = r.ropef
|
||||
template `~`*(r: string): Rope = r % []
|
||||
else:
|
||||
{.push stack_trace: off, line_trace: off.}
|
||||
proc `~`*(r: static[string]): PRope =
|
||||
proc `~`*(r: static[string]): Rope =
|
||||
# this is the new optimized "to rope" operator
|
||||
# the mnemonic is that `~` looks a bit like a rope :)
|
||||
var r {.global.} = r.ropef
|
||||
var r {.global.} = r % []
|
||||
return r
|
||||
{.pop.}
|
||||
|
||||
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
||||
app(c, ropef(frmt, args))
|
||||
|
||||
const
|
||||
bufSize = 1024 # 1 KB is reasonable
|
||||
|
||||
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
|
||||
if r.data != nil:
|
||||
if r.length > bufSize:
|
||||
errorHandler(rTokenTooLong, r.data)
|
||||
return
|
||||
var readBytes = readBuffer(bin, buf, r.length)
|
||||
result = readBytes == r.length and
|
||||
equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
|
||||
else:
|
||||
result = auxRopeEqualsFile(r.left, bin, buf)
|
||||
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
||||
proc equalsFile*(r: Rope, f: File): bool =
|
||||
## returns true if the contents of the file `f` equal `r`.
|
||||
var
|
||||
buf: array[bufSize, char]
|
||||
bpos = buf.len
|
||||
blen = buf.len
|
||||
|
||||
proc ropeEqualsFile(r: PRope, f: string): bool =
|
||||
var bin: File
|
||||
result = open(bin, f)
|
||||
if not result:
|
||||
return # not equal if file does not exist
|
||||
var buf = alloc(bufSize)
|
||||
result = auxRopeEqualsFile(r, bin, buf)
|
||||
for s in leaves(r):
|
||||
var spos = 0
|
||||
let slen = s.len
|
||||
while spos < slen:
|
||||
if bpos == blen:
|
||||
# Read more data
|
||||
bpos = 0
|
||||
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||
if blen == 0: # no more data in file
|
||||
result = false
|
||||
return
|
||||
let n = min(blen - bpos, slen - spos)
|
||||
# TODO There's gotta be a better way of comparing here...
|
||||
if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
|
||||
result = false
|
||||
return
|
||||
spos += n
|
||||
bpos += n
|
||||
|
||||
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
|
||||
|
||||
proc equalsFile*(r: Rope, filename: string): bool =
|
||||
## returns true if the contents of the file `f` equal `r`. If `f` does not
|
||||
## exist, false is returned.
|
||||
var f: File
|
||||
result = open(f, filename)
|
||||
if result:
|
||||
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
|
||||
dealloc(buf)
|
||||
close(bin)
|
||||
result = equalsFile(r, f)
|
||||
close(f)
|
||||
|
||||
proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
|
||||
if r.data != nil:
|
||||
result = startVal
|
||||
for i in countup(0, len(r.data) - 1):
|
||||
result = updateCrc32(r.data[i], result)
|
||||
else:
|
||||
result = crcFromRopeAux(r.left, startVal)
|
||||
result = crcFromRopeAux(r.right, result)
|
||||
|
||||
proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
|
||||
# XXX profiling shows this is actually expensive
|
||||
var stack: TRopeSeq = @[r]
|
||||
result = startVal
|
||||
while len(stack) > 0:
|
||||
var it = pop(stack)
|
||||
while it.data == nil:
|
||||
add(stack, it.right)
|
||||
it = it.left
|
||||
assert(it.data != nil)
|
||||
var i = 0
|
||||
var L = len(it.data)
|
||||
while i < L:
|
||||
result = updateCrc32(it.data[i], result)
|
||||
inc(i)
|
||||
|
||||
proc crcFromRope(r: PRope): TCrc32 =
|
||||
result = newCrcFromRopeAux(r, InitCrc32)
|
||||
|
||||
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
|
||||
proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
|
||||
# returns true if overwritten
|
||||
var c: TCrc32
|
||||
c = crcFromFile(filename)
|
||||
if c != crcFromRope(r):
|
||||
if not equalsFile(r, filename):
|
||||
writeRope(r, filename)
|
||||
result = true
|
||||
else:
|
||||
|
||||
@@ -16,7 +16,7 @@ import
|
||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
|
||||
semparallel, lowerings
|
||||
semparallel, lowerings, plugins
|
||||
|
||||
when defined(nimfix):
|
||||
import nimfix.prettybase
|
||||
@@ -398,7 +398,7 @@ proc myOpen(module: PSym): PPassContext =
|
||||
c.semInferredLambda = semInferredLambda
|
||||
c.semGenerateInstance = generateInstance
|
||||
c.semTypeNode = semTypeNode
|
||||
c.instDeepCopy = sigmatch.instDeepCopy
|
||||
c.instTypeBoundOp = sigmatch.instTypeBoundOp
|
||||
|
||||
pushProcCon(c, module)
|
||||
pushOwner(c.module)
|
||||
|
||||
@@ -7,111 +7,84 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements lifting for assignments and ``deepCopy``.
|
||||
## This module implements lifting for assignments. Later versions of this code
|
||||
## will be able to also lift ``=deepCopy`` and ``=destroy``.
|
||||
|
||||
# included from sem.nim
|
||||
|
||||
type
|
||||
TTypeAttachedOp = enum
|
||||
attachedDestructor,
|
||||
attachedAsgn,
|
||||
attachedDeepCopy
|
||||
|
||||
TLiftCtx = object
|
||||
c: PContext
|
||||
info: TLineInfo # for construction
|
||||
result: PNode
|
||||
kind: TTypeAttachedOp
|
||||
fn: PSym
|
||||
asgnForType: PType
|
||||
recurse: bool
|
||||
|
||||
type
|
||||
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
|
||||
tupleType: PType # if != nil we're traversing a tuple
|
||||
tupleIndex: int
|
||||
field: PSym
|
||||
replaceByFieldName: bool
|
||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
||||
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
|
||||
|
||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
proc at(a, i: PNode, elemType: PType): PNode =
|
||||
result = newNodeI(nkBracketExpr, a.info, 2)
|
||||
result.sons[0] = a
|
||||
result.sons[1] = i
|
||||
result.typ = elemType
|
||||
|
||||
proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
for i in 0 .. <t.len:
|
||||
let lit = lowerings.newIntLit(i)
|
||||
liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
|
||||
|
||||
proc dotField(x: PNode, f: PSym): PNode =
|
||||
result = newNodeI(nkDotExpr, x.info, 2)
|
||||
result.sons[0] = x
|
||||
result.sons[1] = newSymNode(f, x.info)
|
||||
result.typ = f.typ
|
||||
|
||||
proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
||||
of nkIdent:
|
||||
result = n
|
||||
var L = sonsLen(forLoop)
|
||||
if c.replaceByFieldName:
|
||||
if n.ident.id == forLoop[0].ident.id:
|
||||
let fieldName = if c.tupleType.isNil: c.field.name.s
|
||||
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
|
||||
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
|
||||
result = newStrNode(nkStrLit, fieldName)
|
||||
return
|
||||
# other fields:
|
||||
for i in ord(c.replaceByFieldName)..L-3:
|
||||
if n.ident.id == forLoop[i].ident.id:
|
||||
var call = forLoop.sons[L-2]
|
||||
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
|
||||
if c.field.isNil:
|
||||
result = newNodeI(nkBracketExpr, n.info)
|
||||
result.add(tupl)
|
||||
result.add(newIntNode(nkIntLit, c.tupleIndex))
|
||||
else:
|
||||
result = newNodeI(nkDotExpr, n.info)
|
||||
result.add(tupl)
|
||||
result.add(newSymNode(c.field, n.info))
|
||||
break
|
||||
else:
|
||||
if n.kind == nkContinueStmt:
|
||||
localError(n.info, errGenerated,
|
||||
"'continue' not supported in a 'fields' loop")
|
||||
result = copyNode(n)
|
||||
newSons(result, sonsLen(n))
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
|
||||
|
||||
proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) =
|
||||
case typ.kind
|
||||
of nkSym:
|
||||
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
|
||||
fc.field = typ.sym
|
||||
fc.replaceByFieldName = c.m == mFieldPairs
|
||||
openScope(c.c)
|
||||
inc c.c.inUnrolledContext
|
||||
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
||||
father.add(semStmt(c.c, body))
|
||||
dec c.c.inUnrolledContext
|
||||
closeScope(c.c)
|
||||
let f = n.sym
|
||||
liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f))
|
||||
of nkNilLit: discard
|
||||
of nkRecCase:
|
||||
let L = forLoop.len
|
||||
let call = forLoop.sons[L-2]
|
||||
if call.len > 2:
|
||||
localError(forLoop.info, errGenerated,
|
||||
"parallel 'fields' iterator does not work for 'case' objects")
|
||||
return
|
||||
# iterate over the selector:
|
||||
asgnForObjectFields(c, typ[0], forLoop, father)
|
||||
# copy the selector:
|
||||
liftBodyObj(c, n[0], body, x, y)
|
||||
# we need to generate a case statement:
|
||||
var caseStmt = newNodeI(nkCaseStmt, c.info)
|
||||
# XXX generate 'if' that checks same branches
|
||||
# generate selector:
|
||||
var access = newNodeI(nkDotExpr, forLoop.info, 2)
|
||||
access.sons[0] = call.sons[1]
|
||||
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
|
||||
caseStmt.add(semExprWithType(c.c, access))
|
||||
var access = dotField(x, n[0].sym)
|
||||
caseStmt.add(access)
|
||||
# copy the branches over, but replace the fields with the for loop body:
|
||||
for i in 1 .. <typ.len:
|
||||
var branch = copyTree(typ[i])
|
||||
for i in 1 .. <n.len:
|
||||
var branch = copyTree(n[i])
|
||||
let L = branch.len
|
||||
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
|
||||
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
|
||||
caseStmt.add(branch)
|
||||
father.add(caseStmt)
|
||||
of nkRecList:
|
||||
for t in items(typ): liftBodyObj(c, t, x, y)
|
||||
else:
|
||||
illFormedAstLocal(typ)
|
||||
branch.sons[L-1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
proc newAsgnCall(op: PSym; x, y: PNode): PNode =
|
||||
liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
|
||||
caseStmt.add(branch)
|
||||
body.add(caseStmt)
|
||||
localError(c.info, "cannot lift assignment operator to 'case' object")
|
||||
of nkRecList:
|
||||
for t in items(n): liftBodyObj(c, t, body, x, y)
|
||||
else:
|
||||
illFormedAstLocal(n)
|
||||
|
||||
proc genAddr(c: PContext; x: PNode): PNode =
|
||||
if x.kind == nkHiddenDeref:
|
||||
checkSonsLen(x, 1)
|
||||
result = x.sons[0]
|
||||
else:
|
||||
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
|
||||
addSon(result, x)
|
||||
|
||||
proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
|
||||
if sfError in op.flags:
|
||||
localError(x.info, errWrongSymbolX, op.name.s)
|
||||
result = newNodeI(nkCall, x.info)
|
||||
result.add(newSymNode(op))
|
||||
result.add x
|
||||
result.add newSymNode(op)
|
||||
result.add genAddr(c, x)
|
||||
result.add y
|
||||
|
||||
proc newAsgnStmt(le, ri: PNode): PNode =
|
||||
@@ -127,63 +100,124 @@ proc newDestructorCall(op: PSym; x: PNode): PNode =
|
||||
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
||||
result = newAsgnStmt(x, newDestructorCall(op, y))
|
||||
|
||||
proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool =
|
||||
let op = t.attachedOps[c.kind]
|
||||
if op != nil:
|
||||
markUsed(c.info, op)
|
||||
styleCheckUse(c.info, op)
|
||||
case c.kind
|
||||
of attachedDestructor:
|
||||
c.result.add newDestructorCall(op, x)
|
||||
of attachedAsgn:
|
||||
c.result.add newAsgnCall(op, x, y)
|
||||
of attachedDeepCopy:
|
||||
c.result.add newDeepCopyCall(op, x, y)
|
||||
result = true
|
||||
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
case c.kind
|
||||
of attachedDestructor:
|
||||
let op = t.destructor
|
||||
if op != nil:
|
||||
markUsed(c.info, op)
|
||||
styleCheckUse(c.info, op)
|
||||
body.add newDestructorCall(op, x)
|
||||
result = true
|
||||
of attachedAsgn:
|
||||
if tfHasAsgn in t.flags:
|
||||
var op: PSym
|
||||
if sameType(t, c.asgnForType):
|
||||
# generate recursive call:
|
||||
if c.recurse:
|
||||
op = c.fn
|
||||
else:
|
||||
c.recurse = true
|
||||
return false
|
||||
else:
|
||||
op = t.assignment
|
||||
if op == nil:
|
||||
op = liftBody(c.c, t, c.info)
|
||||
markUsed(c.info, op)
|
||||
styleCheckUse(c.info, op)
|
||||
body.add newAsgnCall(c.c, op, x, y)
|
||||
result = true
|
||||
of attachedDeepCopy:
|
||||
let op = t.deepCopy
|
||||
if op != nil:
|
||||
markUsed(c.info, op)
|
||||
styleCheckUse(c.info, op)
|
||||
body.add newDeepCopyCall(op, x, y)
|
||||
result = true
|
||||
|
||||
proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) =
|
||||
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind != attachedDestructor:
|
||||
c.result.add newAsgnStmt(x, y)
|
||||
body.add newAsgnStmt(x, y)
|
||||
|
||||
proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
|
||||
const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [
|
||||
(proc (t: PType, closure: PObject): bool =
|
||||
t.attachedOp[attachedDestructor] != nil),
|
||||
(proc (t: PType, closure: PObject): bool =
|
||||
t.attachedOp[attachedAsgn] != nil),
|
||||
(proc (t: PType, closure: PObject): bool =
|
||||
t.attachedOp[attachedDeepCopy] != nil)]
|
||||
proc addVar(father, v, value: PNode) =
|
||||
var vpart = newNodeI(nkIdentDefs, v.info, 3)
|
||||
vpart.sons[0] = v
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = value
|
||||
addSon(father, vpart)
|
||||
|
||||
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
|
||||
temp.typ = getSysType(tyInt)
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, c.info)
|
||||
result = newSymNode(temp)
|
||||
v.addVar(result, lowerings.newIntLit(first))
|
||||
body.add v
|
||||
|
||||
proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
|
||||
result = newNodeI(nkCall, i.info)
|
||||
result.add createMagic(name, magic).newSymNode
|
||||
result.add i
|
||||
|
||||
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
|
||||
result = newNodeI(nkWhileStmt, c.info, 2)
|
||||
let cmp = genBuiltin(mLeI, "<=", i)
|
||||
cmp.add genHigh(dest)
|
||||
cmp.typ = getSysType(tyBool)
|
||||
result.sons[0] = cmp
|
||||
result.sons[1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
proc addIncStmt(body, i: PNode) =
|
||||
let incCall = genBuiltin(mInc, "inc", i)
|
||||
incCall.add lowerings.newIntLit(1)
|
||||
body.add incCall
|
||||
|
||||
proc newSeqCall(c: PContext; x, y: PNode): PNode =
|
||||
# don't call genAddr(c, x) here:
|
||||
result = genBuiltin(mNewSeq, "newSeq", x)
|
||||
let lenCall = genBuiltin(mLengthSeq, "len", y)
|
||||
lenCall.typ = getSysType(tyInt)
|
||||
result.add lenCall
|
||||
|
||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
of tyNone, tyEmpty: discard
|
||||
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString:
|
||||
defaultOp(c, t, x, y)
|
||||
of tyPtr, tyString:
|
||||
if not considerOverloadedOp(c, t, x, y):
|
||||
defaultOp(c, t, x, y)
|
||||
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
|
||||
tyPtr, tyString, tyRef:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyArrayConstr, tyArray, tySequence:
|
||||
if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil):
|
||||
# generate loop and call the attached Op:
|
||||
|
||||
if tfHasAsgn in t.flags:
|
||||
if t.kind == tySequence:
|
||||
# XXX add 'nil' handling here
|
||||
body.add newSeqCall(c.c, x, y)
|
||||
let i = declareCounter(c, body, firstOrd(t))
|
||||
let whileLoop = genWhileLoop(c, i, x)
|
||||
let elemType = t.lastSon
|
||||
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
|
||||
y.at(i, elemType))
|
||||
addIncStmt(whileLoop.sons[1], i)
|
||||
body.add whileLoop
|
||||
else:
|
||||
defaultOp(c, t, x, y)
|
||||
of tyObject:
|
||||
liftBodyObj(c, t.n, x, y)
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyObject, tyDistinct:
|
||||
if not considerOverloadedOp(c, t, body, x, y):
|
||||
if t.sons[0] != nil: liftBodyAux(c, t.sons[0], body, x, y)
|
||||
if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
|
||||
of tyTuple:
|
||||
liftBodyTup(c, t, x, y)
|
||||
of tyRef:
|
||||
# we MUST NOT check for acyclic here as a DAG might still share nodes:
|
||||
|
||||
liftBodyTup(c, t, body, x, y)
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure or c.kind != attachedDeepCopy:
|
||||
defaultOp(c, t, x, y)
|
||||
defaultOp(c, t, body, x, y)
|
||||
else:
|
||||
# a big problem is that we don't know the enviroment's type here, so we
|
||||
# have to go through some indirection; we delegate this to the codegen:
|
||||
call = newNodeI(nkCall, n.info, 2)
|
||||
let call = newNodeI(nkCall, c.info, 2)
|
||||
call.typ = t
|
||||
call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
||||
call.sons[1] = y
|
||||
c.result.add newAsgnStmt(x, call)
|
||||
body.add newAsgnStmt(x, call)
|
||||
of tyVarargs, tyOpenArray:
|
||||
localError(c.info, errGenerated, "cannot copy openArray")
|
||||
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
@@ -191,13 +225,60 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
|
||||
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
|
||||
tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
|
||||
internalError(c.info, "assignment requested for type: " & typeToString(t))
|
||||
of tyDistinct, tyOrdinal, tyRange,
|
||||
of tyOrdinal, tyRange,
|
||||
tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
|
||||
liftBodyAux(c, lastSon(t))
|
||||
liftBodyAux(c, lastSon(t), body, x, y)
|
||||
|
||||
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode =
|
||||
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
||||
result = newType(tyProc, owner)
|
||||
result.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result, nil) # return type
|
||||
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
||||
# the effects are now stored in there too ... this is a bit hacky, but as
|
||||
# usual we desperately try to save memory:
|
||||
addSon(result.n, newNodeI(nkEffectList, info))
|
||||
|
||||
proc addParam(procType: PType; param: PSym) =
|
||||
param.position = procType.len-1
|
||||
addSon(procType.n, newSymNode(param))
|
||||
rawAddSon(procType, param.typ)
|
||||
|
||||
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
a.result = newNodeI(nkStmtList, info)
|
||||
liftBodyAux(a, typ)
|
||||
result = a.result
|
||||
let body = newNodeI(nkStmtList, info)
|
||||
result = newSym(skProc, getIdent":lifted=", typ.owner, info)
|
||||
a.fn = result
|
||||
a.asgnForType = typ
|
||||
|
||||
let dest = newSym(skParam, getIdent"dest", result, info)
|
||||
let src = newSym(skParam, getIdent"src", result, info)
|
||||
dest.typ = makeVarType(c, typ)
|
||||
src.typ = typ
|
||||
|
||||
result.typ = newProcType(info, typ.owner)
|
||||
result.typ.addParam dest
|
||||
result.typ.addParam src
|
||||
|
||||
liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
|
||||
|
||||
var n = newNodeI(nkProcDef, info, bodyPos+1)
|
||||
for i in 0 .. < n.len: n.sons[i] = emptyNode
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
n.sons[paramsPos] = result.typ.n
|
||||
n.sons[bodyPos] = body
|
||||
result.ast = n
|
||||
|
||||
# register late as recursion is handled differently
|
||||
typ.assignment = result
|
||||
#echo "Produced this ", n
|
||||
|
||||
proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
||||
let t = typ.skipTypes({tyGenericInst, tyVar})
|
||||
result = t.assignment
|
||||
if result.isNil:
|
||||
result = liftBody(c, t, info)
|
||||
|
||||
proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
|
||||
let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
|
||||
result = newAsgnCall(c, a, dest, src)
|
||||
|
||||
@@ -43,10 +43,16 @@ type
|
||||
inst*: PInstantiation
|
||||
|
||||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
||||
efLValue, efWantIterator, efInTypeof,
|
||||
efWantStmt, efAllowStmt, efDetermineType,
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
TTypeAttachedOp* = enum
|
||||
attachedAsgn,
|
||||
attachedDeepCopy,
|
||||
attachedDestructor
|
||||
|
||||
PContext* = ref TContext
|
||||
TContext* = object of TPassContext # a context represents a module
|
||||
module*: PSym # the module sym belonging to the context
|
||||
@@ -93,8 +99,8 @@ type
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||
inParallelStmt*: int
|
||||
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||
info: TLineInfo): PSym {.nimcall.}
|
||||
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
op: TTypeAttachedOp): PSym {.nimcall.}
|
||||
|
||||
|
||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||
@@ -112,7 +118,6 @@ proc newOptionEntry*(): POptionEntry
|
||||
proc newLib*(kind: TLibKind): PLib
|
||||
proc addToLib*(lib: PLib, sym: PSym)
|
||||
proc makePtrType*(c: PContext, baseType: PType): PType
|
||||
proc makeVarType*(c: PContext, baseType: PType): PType
|
||||
proc newTypeS*(kind: TTypeKind, c: PContext): PType
|
||||
proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext)
|
||||
|
||||
@@ -207,9 +212,12 @@ proc makePtrType(c: PContext, baseType: PType): PType =
|
||||
result = newTypeS(tyPtr, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeVarType(c: PContext, baseType: PType): PType =
|
||||
result = newTypeS(tyVar, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
proc makeVarType*(c: PContext, baseType: PType): PType =
|
||||
if baseType.kind == tyVar:
|
||||
result = baseType
|
||||
else:
|
||||
result = newTypeS(tyVar, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
@@ -241,6 +249,7 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc makeOrType*(c: PContext, t1, t2: PType): PType =
|
||||
result = newTypeS(tyOr, c)
|
||||
@@ -248,12 +257,14 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
|
||||
propagateToOwner(result, t1)
|
||||
propagateToOwner(result, t2)
|
||||
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc makeNotType*(c: PContext, t1: PType): PType =
|
||||
result = newTypeS(tyNot, c)
|
||||
result.sons = @[t1]
|
||||
propagateToOwner(result, t1)
|
||||
result.flags.incl(t1.flags * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc nMinusOne*(n: PNode): PNode =
|
||||
result = newNode(nkCall, n.info, @[
|
||||
|
||||
@@ -31,7 +31,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if result.typ != nil:
|
||||
# XXX tyGenericInst here?
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
elif efWantStmt in flags:
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyEmpty, c)
|
||||
else:
|
||||
localError(n.info, errExprXHasNoType,
|
||||
@@ -389,7 +389,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||
maybeLiftType(t2, c, n.info)
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, t2)
|
||||
let match = typeRel(m, t2, t1) != isNone
|
||||
let match = typeRel(m, t2, t1) >= isSubtype # isNone
|
||||
result = newIntNode(nkIntLit, ord(match))
|
||||
|
||||
result.typ = n.typ
|
||||
@@ -1298,6 +1298,9 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||
typeMismatch(n, lhs.typ, rhs.typ)
|
||||
|
||||
n.sons[1] = fitNode(c, le, rhs)
|
||||
if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
|
||||
return overloadedAsgn(c, lhs, n.sons[1])
|
||||
|
||||
fixAbstractType(c, n)
|
||||
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
||||
result = n
|
||||
|
||||
@@ -118,6 +118,9 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
|
||||
let lowerNode = newIntNode(nkIntLit, minA)
|
||||
if typ.kind == tyInt and minA == maxA:
|
||||
result = getIntLitType(lowerNode)
|
||||
elif typ.kind in {tyUint, tyUInt64}:
|
||||
# these are not ordinal types, so you get no subrange type for these:
|
||||
result = typ
|
||||
else:
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, lowerNode)
|
||||
@@ -135,8 +138,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
|
||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
# Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
|
||||
# Nim requires interval arithmetic for ``range`` types. Lots of tedious
|
||||
# work but the feature is very nice for reducing explicit conversions.
|
||||
const ordIntLit = {nkIntLit..nkUInt64Lit}
|
||||
result = n.typ
|
||||
|
||||
template commutativeOp(opr: expr) {.immediate.} =
|
||||
@@ -170,13 +174,19 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
let a = n.sons[1].typ
|
||||
if isFloatRange(a):
|
||||
# abs(-5.. 1) == (1..5)
|
||||
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
|
||||
abs(getFloat(a.n.sons[0])))
|
||||
if a.n[0].floatVal <= 0.0:
|
||||
result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
|
||||
else:
|
||||
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
|
||||
abs(getFloat(a.n.sons[0])))
|
||||
of mAbsI, mAbsI64:
|
||||
let a = n.sons[1].typ
|
||||
if isIntRange(a):
|
||||
result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
|
||||
`|abs|`(getInt(a.n.sons[0])))
|
||||
if a.n[0].intVal <= 0:
|
||||
result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
|
||||
else:
|
||||
result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
|
||||
`|abs|`(getInt(a.n.sons[0])))
|
||||
of mSucc:
|
||||
let a = n.sons[1].typ
|
||||
let b = n.sons[2].typ
|
||||
@@ -202,15 +212,15 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
var a = n.sons[1]
|
||||
var b = n.sons[2]
|
||||
# symmetrical:
|
||||
if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
|
||||
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||
if b.kind notin ordIntLit: swap(a, b)
|
||||
if b.kind in ordIntLit:
|
||||
let x = b.intVal|+|1
|
||||
if (x and -x) == x and x >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal)
|
||||
of mModU:
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||
if a.kind in ordIntLit:
|
||||
if b.intVal >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal-1)
|
||||
else:
|
||||
@@ -226,9 +236,9 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
|
||||
of mDivI, mDivI64, mDivU:
|
||||
binaryOp(`|div|`)
|
||||
of mMinI, mMinI64:
|
||||
of mMinI:
|
||||
commutativeOp(min)
|
||||
of mMaxI, mMaxI64:
|
||||
of mMaxI:
|
||||
commutativeOp(max)
|
||||
else: discard
|
||||
|
||||
@@ -276,10 +286,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
|
||||
of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
|
||||
of mLengthStr: result = newIntNodeT(len(getStr(a)), n)
|
||||
of mLengthStr, mXLenStr: result = newIntNodeT(len(getStr(a)), n)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
|
||||
of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX
|
||||
of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
|
||||
of mLengthSeq, mLengthOpenArray, mXLenSeq:
|
||||
result = newIntNodeT(sonsLen(a), n) # BUGFIX
|
||||
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
||||
of mToFloat, mToBiggestFloat:
|
||||
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||
@@ -299,10 +310,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
|
||||
of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
|
||||
of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
|
||||
of mMinI, mMinI64:
|
||||
of mMinI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
|
||||
else: result = newIntNodeT(getInt(a), n)
|
||||
of mMaxI, mMaxI64:
|
||||
of mMaxI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
|
||||
else: result = newIntNodeT(getInt(b), n)
|
||||
of mShlI, mShlI64:
|
||||
|
||||
@@ -176,7 +176,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
|
||||
for i in 1 .. <result.len:
|
||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||
if i > 1: resetIdTable(cl.symMap)
|
||||
if i > 1:
|
||||
resetIdTable(cl.symMap)
|
||||
resetIdTable(cl.localCache)
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
internalAssert originalParams[i].kind == nkSym
|
||||
@@ -196,6 +198,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
addDecl(c, result.n.sons[i].sym)
|
||||
|
||||
resetIdTable(cl.symMap)
|
||||
resetIdTable(cl.localCache)
|
||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||
result.n.sons[0] = originalParams[0].copyTree
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||
result.typ = newType(tyString, context)
|
||||
result.info = trait.info
|
||||
of "arity":
|
||||
result = newIntNode(nkIntLit, typ.n.len-1)
|
||||
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
||||
result.typ = newType(tyInt, context)
|
||||
result.info = trait.info
|
||||
else:
|
||||
@@ -196,4 +196,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result.add newSymNode(createMagic("-", mSubI), n.info)
|
||||
result.add lenExprB
|
||||
result.add n.sons[1]
|
||||
of mPlugin:
|
||||
let plugin = getPlugin(n[0].sym)
|
||||
if plugin.isNil:
|
||||
localError(n.info, "cannot find plugin " & n[0].sym.name.s)
|
||||
result = n
|
||||
else:
|
||||
result = plugin(c, n)
|
||||
else: result = n
|
||||
|
||||
@@ -194,8 +194,38 @@ proc warnAboutGcUnsafe(n: PNode) =
|
||||
#assert false
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
|
||||
template markGcUnsafe(a: PEffects) =
|
||||
proc markGcUnsafe(a: PEffects; reason: PSym) =
|
||||
a.gcUnsafe = true
|
||||
if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
|
||||
|
||||
proc markGcUnsafe(a: PEffects; reason: PNode) =
|
||||
a.gcUnsafe = true
|
||||
if a.owner.kind in routineKinds:
|
||||
if reason.kind == nkSym:
|
||||
a.owner.gcUnsafetyReason = reason.sym
|
||||
else:
|
||||
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
|
||||
a.owner, reason.info)
|
||||
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
||||
let u = s.gcUnsafetyReason
|
||||
if u != nil:
|
||||
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
|
||||
if u.kind in {skLet, skVar}:
|
||||
message(s.info, msgKind,
|
||||
("'$#' is not GC-safe as it accesses '$#'" &
|
||||
" which is a global using GC'ed memory") % [s.name.s, u.name.s])
|
||||
elif u.kind in routineKinds:
|
||||
# recursive call *always* produces only a warning so the full error
|
||||
# message is printed:
|
||||
listGcUnsafety(u, true)
|
||||
message(s.info, msgKind,
|
||||
"'$#' is not GC-safe as it calls '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
else:
|
||||
internalAssert u.kind == skUnknown
|
||||
message(u.info, msgKind,
|
||||
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
@@ -210,8 +240,8 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
|
||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(a)
|
||||
#if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(a, s)
|
||||
|
||||
type
|
||||
TIntersection = seq[tuple[id, count: int]] # a simple count table
|
||||
@@ -450,7 +480,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
|
||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(tracked)
|
||||
markGcUnsafe(tracked, s)
|
||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
@@ -504,13 +534,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(tracked)
|
||||
markGcUnsafe(tracked, a)
|
||||
else:
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(tracked)
|
||||
markGcUnsafe(tracked, a)
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
@@ -658,7 +688,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# and it's not a recursive call:
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(tracked)
|
||||
markGcUnsafe(tracked, a)
|
||||
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
# may not look like an assignment, but it is:
|
||||
@@ -734,7 +764,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
setLen(tracked.locked, oldLocked)
|
||||
tracked.currLockLevel = oldLockLevel
|
||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||
nkMacroDef, nkTemplateDef:
|
||||
nkMacroDef, nkTemplateDef, nkLambda, nkDo:
|
||||
discard
|
||||
else:
|
||||
for i in 0 .. <safeLen(n): track(tracked, n.sons[i])
|
||||
@@ -853,9 +883,11 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
listGcUnsafety(s, onlyWarning=false)
|
||||
else:
|
||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
listGcUnsafety(s, onlyWarning=true)
|
||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if not t.gcUnsafe:
|
||||
s.typ.flags.incl tfGcSafe
|
||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||
|
||||
@@ -340,6 +340,39 @@ proc checkNilable(v: PSym) =
|
||||
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||
message(v.info, warnProveInit, v.name.s)
|
||||
|
||||
include semasgn
|
||||
|
||||
proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
|
||||
# consider this:
|
||||
# var
|
||||
# x = 0
|
||||
# withOverloadedAssignment = foo()
|
||||
# y = use(withOverloadedAssignment)
|
||||
# We need to split this into a statement list with multiple 'var' sections
|
||||
# in order for this transformation to be correct.
|
||||
let L = identDefs.len
|
||||
let value = identDefs[L-1]
|
||||
if value.typ != nil and tfHasAsgn in value.typ.flags:
|
||||
# the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()':
|
||||
identDefs.sons[L-1] = emptyNode
|
||||
if result.kind != nkStmtList:
|
||||
let oldResult = result
|
||||
oldResult.add identDefs
|
||||
result = newNodeI(nkStmtList, result.info)
|
||||
result.add oldResult
|
||||
else:
|
||||
let o = copyNode(orig)
|
||||
o.add identDefs
|
||||
result.add o
|
||||
for i in 0 .. L-3:
|
||||
result.add overloadedAsgn(c, identDefs[i], value)
|
||||
elif result.kind == nkStmtList:
|
||||
let o = copyNode(orig)
|
||||
o.add identDefs
|
||||
result.add o
|
||||
else:
|
||||
result.add identDefs
|
||||
|
||||
proc isDiscardUnderscore(n: PNode): bool =
|
||||
if n.kind != nkIdent: return false
|
||||
return n.ident.s == "_"
|
||||
@@ -400,7 +433,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
newSons(b, length)
|
||||
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
||||
b.sons[length-1] = def
|
||||
addSon(result, b)
|
||||
addToVarSection(c, result, n, b)
|
||||
elif tup.kind == tyTuple and def.kind == nkPar and
|
||||
a.kind == nkIdentDefs and a.len > 3:
|
||||
message(a.info, warnEachIdentIsTuple)
|
||||
@@ -434,7 +467,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
addSon(b, newSymNode(v))
|
||||
addSon(b, a.sons[length-2]) # keep type desc for doc generator
|
||||
addSon(b, copyTree(def))
|
||||
addSon(result, b)
|
||||
addToVarSection(c, result, n, b)
|
||||
else:
|
||||
if def.kind == nkPar: v.ast = def[j]
|
||||
v.typ = tup.sons[j]
|
||||
@@ -659,6 +692,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||
#debug s.typ
|
||||
s.ast = a
|
||||
popOwner()
|
||||
let aa = a.sons[2]
|
||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
||||
aa.sons[0].kind == nkObjectTy:
|
||||
# give anonymous object a dummy symbol:
|
||||
var st = s.typ
|
||||
if st.kind == tyGenericBody: st = st.lastSon
|
||||
internalAssert st.kind in {tyPtr, tyRef}
|
||||
internalAssert st.lastSon.sym == nil
|
||||
st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
|
||||
getCurrOwner(), s.info)
|
||||
|
||||
proc checkForMetaFields(n: PNode) =
|
||||
template checkMeta(t) =
|
||||
@@ -702,16 +745,6 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
checkConstructedType(s.info, s.typ)
|
||||
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||
checkForMetaFields(s.typ.n)
|
||||
let aa = a.sons[2]
|
||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
||||
aa.sons[0].kind == nkObjectTy:
|
||||
# give anonymous object a dummy symbol:
|
||||
var st = s.typ
|
||||
if st.kind == tyGenericBody: st = st.lastSon
|
||||
internalAssert st.kind in {tyPtr, tyRef}
|
||||
internalAssert st.lastSon.sym == nil
|
||||
st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
|
||||
getCurrOwner(), s.info)
|
||||
|
||||
proc semTypeSection(c: PContext, n: PNode): PNode =
|
||||
## Processes a type section. This must be done in separate passes, in order
|
||||
@@ -914,11 +947,12 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||
|
||||
proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
case s.name.s.normalize
|
||||
of "destroy":
|
||||
of "destroy", "=destroy":
|
||||
doDestructorStuff(c, s, n)
|
||||
if not experimentalMode(c):
|
||||
localError n.info, "use the {.experimental.} pragma to enable destructors"
|
||||
of "deepcopy":
|
||||
incl(s.flags, sfUsed)
|
||||
of "deepcopy", "=deepcopy":
|
||||
if s.typ.len == 2 and
|
||||
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
|
||||
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||
@@ -940,10 +974,35 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
else:
|
||||
localError(n.info, errGenerated,
|
||||
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
||||
of "=": discard
|
||||
else: localError(n.info, errGenerated,
|
||||
"'destroy' or 'deepCopy' expected for 'override'")
|
||||
incl(s.flags, sfUsed)
|
||||
incl(s.flags, sfUsed)
|
||||
of "=":
|
||||
incl(s.flags, sfUsed)
|
||||
let t = s.typ
|
||||
if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
|
||||
var obj = t.sons[1].sons[0]
|
||||
while true:
|
||||
incl(obj.flags, tfHasAsgn)
|
||||
if obj.kind == tyGenericBody: obj = obj.lastSon
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
|
||||
else: break
|
||||
var objB = t.sons[2]
|
||||
while true:
|
||||
if objB.kind == tyGenericBody: objB = objB.lastSon
|
||||
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
|
||||
if obj.assignment.isNil:
|
||||
obj.assignment = s
|
||||
else:
|
||||
localError(n.info, errGenerated,
|
||||
"cannot bind another '=' to: " & typeToString(obj))
|
||||
return
|
||||
localError(n.info, errGenerated,
|
||||
"signature for '=' must be proc[T: object](x: var T; y: T)")
|
||||
else:
|
||||
if sfOverriden in s.flags:
|
||||
localError(n.info, errGenerated,
|
||||
"'destroy' or 'deepCopy' expected for 'override'")
|
||||
|
||||
type
|
||||
TProcCompilationSteps = enum
|
||||
@@ -975,7 +1034,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
s = semIdentDef(c, n.sons[0], kind)
|
||||
n.sons[namePos] = newSymNode(s)
|
||||
s.ast = n
|
||||
s.scope = c.currentScope
|
||||
#s.scope = c.currentScope
|
||||
|
||||
if sfNoForward in c.module.flags and
|
||||
sfSystemModule notin c.module.flags:
|
||||
@@ -987,14 +1046,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
s.owner = getCurrOwner()
|
||||
typeIsDetermined = s.typ == nil
|
||||
s.ast = n
|
||||
s.scope = c.currentScope
|
||||
#s.scope = c.currentScope
|
||||
|
||||
# if typeIsDetermined: assert phase == stepCompileBody
|
||||
# else: assert phase == stepDetermineType
|
||||
# before compiling the proc body, set as current the scope
|
||||
# where the proc was declared
|
||||
let oldScope = c.currentScope
|
||||
c.currentScope = s.scope
|
||||
#c.currentScope = s.scope
|
||||
pushOwner(s)
|
||||
openScope(c)
|
||||
var gp: PNode
|
||||
@@ -1019,7 +1078,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if s.kind in skIterators:
|
||||
s.typ.flags.incl(tfIterator)
|
||||
|
||||
var proto = searchForProc(c, s.scope, s)
|
||||
var proto = searchForProc(c, oldScope, s)
|
||||
if proto == nil:
|
||||
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
||||
else: s.typ.callConv = lastOptionEntry(c).defaultCC
|
||||
@@ -1027,10 +1086,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if sfGenSym in s.flags: discard
|
||||
elif kind in OverloadableSyms:
|
||||
if not typeIsDetermined:
|
||||
addInterfaceOverloadableSymAt(c, s.scope, s)
|
||||
addInterfaceOverloadableSymAt(c, oldScope, s)
|
||||
else:
|
||||
if not typeIsDetermined:
|
||||
addInterfaceDeclAt(c, s.scope, s)
|
||||
addInterfaceDeclAt(c, oldScope, s)
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, s, n.sons[pragmasPos], validPragmas)
|
||||
else:
|
||||
@@ -1060,7 +1119,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
popOwner()
|
||||
pushOwner(s)
|
||||
s.options = gOptions
|
||||
if sfOverriden in s.flags: semOverride(c, s, n)
|
||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
# for DLL generation it is annoying to check for sfImportc!
|
||||
if sfBorrow in s.flags:
|
||||
@@ -1098,7 +1157,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||
sideEffectsCheck(c, s)
|
||||
closeScope(c) # close scope for parameters
|
||||
c.currentScope = oldScope
|
||||
# c.currentScope = oldScope
|
||||
popOwner()
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
c.patterns.add(s)
|
||||
|
||||
@@ -482,7 +482,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
||||
styleCheckDef(s)
|
||||
# check parameter list:
|
||||
s.scope = c.currentScope
|
||||
#s.scope = c.currentScope
|
||||
pushOwner(s)
|
||||
openScope(c)
|
||||
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
||||
|
||||
@@ -261,7 +261,8 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
if not isOrdinalType(indx):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(indx):
|
||||
localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
|
||||
localError(n.sons[1].info, errEnumXHasHoles,
|
||||
typeToString(indx.skipTypes({tyRange})))
|
||||
base = semTypeNode(c, n.sons[2], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
@@ -593,7 +594,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
f.position = pos
|
||||
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
|
||||
(f.loc.r == nil):
|
||||
f.loc.r = toRope(f.name.s)
|
||||
f.loc.r = rope(f.name.s)
|
||||
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
|
||||
inc(pos)
|
||||
if containsOrIncl(check, f.name.id):
|
||||
@@ -646,14 +647,17 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||
checkSonsLen(n, 3)
|
||||
if n.sons[1].kind != nkEmpty:
|
||||
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
base = skipTypesOrNil(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||
if base.isNil:
|
||||
localError(n.info, errIllegalRecursionInTypeX, "object")
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
||||
base = nil
|
||||
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
||||
base = nil
|
||||
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
|
||||
result = newOrPrevType(tyObject, prev, c)
|
||||
rawAddSon(result, base)
|
||||
@@ -786,7 +790,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
@[newTypeS(paramType.kind, c)])
|
||||
result = addImplicitGeneric(typ)
|
||||
else:
|
||||
for i in 0 .. <paramType.sons.len:
|
||||
for i in 0 .. <paramType.len:
|
||||
if paramType.sons[i] == paramType:
|
||||
globalError(info, errIllegalRecursionInTypeX, typeToString(paramType))
|
||||
var lifted = liftingWalk(paramType.sons[i])
|
||||
@@ -831,7 +835,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
cp.kind = tyUserTypeClassInst
|
||||
return addImplicitGeneric(cp)
|
||||
|
||||
for i in 1 .. (paramType.sons.len - 2):
|
||||
for i in 1 .. paramType.len-2:
|
||||
var lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil:
|
||||
paramType.sons[i] = lifted
|
||||
@@ -844,7 +848,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
result.shouldHaveMeta
|
||||
|
||||
of tyGenericInvocation:
|
||||
for i in 1 .. <paramType.sonsLen:
|
||||
for i in 1 .. <paramType.len:
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
when false:
|
||||
|
||||
@@ -16,9 +16,9 @@ const
|
||||
|
||||
proc sharedPtrCheck(info: TLineInfo, t: PType) =
|
||||
if t.kind == tyPtr and t.len > 1:
|
||||
if t.sons[0].sym.magic in {mShared, mGuarded}:
|
||||
if t.sons[0].sym.magic == mShared:
|
||||
incl(t.flags, tfShared)
|
||||
if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
|
||||
#if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
|
||||
if tfHasGCedMem in t.flags or t.isGCedMem:
|
||||
localError(info, errGenerated,
|
||||
"shared memory may not refer to GC'ed thread local memory")
|
||||
@@ -233,7 +233,9 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||
# XXX: relying on allowMetaTypes is a kludge
|
||||
result = copyType(t, t.owner, cl.allowMetaTypes)
|
||||
result.flags.incl tfFromGeneric
|
||||
result.flags.excl tfInstClearedFlags
|
||||
if not (t.kind in tyMetaTypes or
|
||||
(t.kind == tyStatic and t.n == nil)):
|
||||
result.flags.excl tfInstClearedFlags
|
||||
|
||||
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||
@@ -307,7 +309,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy)
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn)
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
@@ -412,15 +420,23 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = t
|
||||
|
||||
of tyGenericInst:
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
if result != nil: return result
|
||||
result = instCopyType(cl, t)
|
||||
idTablePut(cl.localCache, t, result)
|
||||
for i in 1 .. <result.sonsLen:
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.lastSon)
|
||||
|
||||
else:
|
||||
if containsGenericType(t):
|
||||
#if not cl.allowMetaTypes:
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
if result != nil: return result
|
||||
result = instCopyType(cl, t)
|
||||
result.size = -1 # needs to be recomputed
|
||||
#if not cl.allowMetaTypes:
|
||||
idTablePut(cl.localCache, t, result)
|
||||
|
||||
for i in countup(0, sonsLen(result) - 1):
|
||||
if result.sons[i] != nil:
|
||||
|
||||
@@ -99,9 +99,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||
c.calleeSym = callee
|
||||
if callee.kind in skProcKinds and calleeScope == -1:
|
||||
if callee.originatingModule == ctx.module:
|
||||
let rootSym = if sfFromGeneric notin callee.flags: callee
|
||||
else: callee.owner
|
||||
c.calleeScope = rootSym.scope.depthLevel
|
||||
c.calleeScope = 2
|
||||
var owner = callee
|
||||
while true:
|
||||
owner = owner.skipGenericOwner
|
||||
if owner.kind == skModule: break
|
||||
inc c.calleeScope
|
||||
else:
|
||||
c.calleeScope = 1
|
||||
else:
|
||||
@@ -1105,8 +1108,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
localError(f.n.info, errTypeExpected)
|
||||
result = isNone
|
||||
|
||||
of tyNone:
|
||||
if a.kind == tyNone: result = isEqual
|
||||
else:
|
||||
internalAssert false
|
||||
internalError " unknown type kind " & $f.kind
|
||||
|
||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||
var m: TCandidate
|
||||
@@ -1419,9 +1424,12 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
|
||||
# a.typ == nil is valid
|
||||
result = a
|
||||
elif a.typ.isNil:
|
||||
# XXX This is unsound! 'formal' can differ from overloaded routine to
|
||||
# overloaded routine!
|
||||
let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
|
||||
elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
|
||||
else: {efDetermineType}
|
||||
else: {efDetermineType, efAllowStmt}
|
||||
#elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
|
||||
#else: {efDetermineType}
|
||||
result = c.semOperand(c, a, flags)
|
||||
else:
|
||||
result = a
|
||||
@@ -1627,12 +1635,15 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
# instantiate generic converters for that
|
||||
result = res != nil
|
||||
|
||||
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
|
||||
procvar.} =
|
||||
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
op: TTypeAttachedOp): PSym {.procvar.} =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, dc.typ)
|
||||
var f = dc.typ.sons[1]
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
if op == attachedDeepCopy:
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
if f.kind == tyVar: f = f.lastSon
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
|
||||
else:
|
||||
|
||||
@@ -9,40 +9,40 @@
|
||||
|
||||
# tree helper routines
|
||||
|
||||
import
|
||||
import
|
||||
ast, astalgo, lexer, msgs, strutils, wordrecg
|
||||
|
||||
proc hasSon(father, son: PNode): bool =
|
||||
for i in countup(0, sonsLen(father) - 1):
|
||||
if father.sons[i] == son:
|
||||
proc hasSon(father, son: PNode): bool =
|
||||
for i in countup(0, sonsLen(father) - 1):
|
||||
if father.sons[i] == son:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc cyclicTreeAux(n, s: PNode): bool =
|
||||
if n == nil:
|
||||
proc cyclicTreeAux(n, s: PNode): bool =
|
||||
if n == nil:
|
||||
return false
|
||||
if hasSon(s, n):
|
||||
if hasSon(s, n):
|
||||
return true
|
||||
var m = sonsLen(s)
|
||||
addSon(s, n)
|
||||
if not (n.kind in {nkEmpty..nkNilLit}):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if cyclicTreeAux(n.sons[i], s):
|
||||
if not (n.kind in {nkEmpty..nkNilLit}):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if cyclicTreeAux(n.sons[i], s):
|
||||
return true
|
||||
result = false
|
||||
delSon(s, m)
|
||||
|
||||
proc cyclicTree*(n: PNode): bool =
|
||||
proc cyclicTree*(n: PNode): bool =
|
||||
var s = newNodeI(nkEmpty, n.info)
|
||||
result = cyclicTreeAux(n, s)
|
||||
|
||||
proc exprStructuralEquivalent*(a, b: PNode): bool =
|
||||
proc exprStructuralEquivalent*(a, b: PNode): bool =
|
||||
result = false
|
||||
if a == b:
|
||||
if a == b:
|
||||
result = true
|
||||
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
||||
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
||||
case a.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
# don't go nuts here: same symbol as string is enough:
|
||||
result = a.sym.name.id == b.sym.name.id
|
||||
of nkIdent: result = a.ident.id == b.ident.id
|
||||
@@ -50,12 +50,12 @@ proc exprStructuralEquivalent*(a, b: PNode): bool =
|
||||
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkEmpty, nkNilLit, nkType: result = true
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
|
||||
proc sameTree*(a, b: PNode): bool =
|
||||
result = false
|
||||
if a == b:
|
||||
@@ -66,7 +66,7 @@ proc sameTree*(a, b: PNode): bool =
|
||||
if a.info.col != b.info.col:
|
||||
return #if a.info.fileIndex <> b.info.fileIndex then exit;
|
||||
case a.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
# don't go nuts here: same symbol as string is enough:
|
||||
result = a.sym.name.id == b.sym.name.id
|
||||
of nkIdent: result = a.ident.id == b.ident.id
|
||||
@@ -75,15 +75,15 @@ proc sameTree*(a, b: PNode): bool =
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkEmpty, nkNilLit, nkType: result = true
|
||||
else:
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
if not sameTree(a.sons[i], b.sons[i]): return
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
if not sameTree(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
proc getProcSym*(call: PNode): PSym =
|
||||
|
||||
proc getProcSym*(call: PNode): PSym =
|
||||
result = call.sons[0].sym
|
||||
|
||||
proc getOpSym*(op: PNode): PSym =
|
||||
proc getOpSym*(op: PNode): PSym =
|
||||
if op.kind notin {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}:
|
||||
result = nil
|
||||
else:
|
||||
@@ -91,25 +91,25 @@ proc getOpSym*(op: PNode): PSym =
|
||||
elif op.sons[0].kind == nkSym: result = op.sons[0].sym
|
||||
else: result = nil
|
||||
|
||||
proc getMagic*(op: PNode): TMagic =
|
||||
proc getMagic*(op: PNode): TMagic =
|
||||
case op.kind
|
||||
of nkCallKinds:
|
||||
case op.sons[0].kind
|
||||
of nkSym: result = op.sons[0].sym.magic
|
||||
else: result = mNone
|
||||
else: result = mNone
|
||||
|
||||
proc treeToSym*(t: PNode): PSym =
|
||||
|
||||
proc treeToSym*(t: PNode): PSym =
|
||||
result = t.sym
|
||||
|
||||
proc isConstExpr*(n: PNode): bool =
|
||||
proc isConstExpr*(n: PNode): bool =
|
||||
result = (n.kind in
|
||||
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
|
||||
|
||||
proc isDeepConstExpr*(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
nkFloatLit..nkFloat64Lit, nkNilLit:
|
||||
result = true
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
|
||||
@@ -122,33 +122,33 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
|
||||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
||||
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
||||
if (getMagic(a) == op): # a is a "leaf", so add it:
|
||||
for i in countup(1, sonsLen(a) - 1): # BUGFIX
|
||||
flattenTreeAux(d, a.sons[i], op)
|
||||
else:
|
||||
else:
|
||||
addSon(d, copyTree(a))
|
||||
|
||||
proc flattenTree*(root: PNode, op: TMagic): PNode =
|
||||
|
||||
proc flattenTree*(root: PNode, op: TMagic): PNode =
|
||||
result = copyNode(root)
|
||||
if getMagic(root) == op:
|
||||
# BUGFIX: forget to copy prc
|
||||
addSon(result, copyNode(root.sons[0]))
|
||||
flattenTreeAux(result, root, op)
|
||||
|
||||
proc swapOperands*(op: PNode) =
|
||||
proc swapOperands*(op: PNode) =
|
||||
var tmp = op.sons[1]
|
||||
op.sons[1] = op.sons[2]
|
||||
op.sons[2] = tmp
|
||||
|
||||
proc isRange*(n: PNode): bool {.inline.} =
|
||||
if n.kind == nkInfix:
|
||||
proc isRange*(n: PNode): bool {.inline.} =
|
||||
if n.kind in nkCallKinds:
|
||||
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
|
||||
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
||||
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
|
||||
n[0][1].sym.name.id == ord(wDotDot):
|
||||
result = true
|
||||
|
||||
proc whichPragma*(n: PNode): TSpecialWord =
|
||||
proc whichPragma*(n: PNode): TSpecialWord =
|
||||
let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
|
||||
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
||||
|
||||
|
||||
@@ -541,6 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
of tyProc:
|
||||
result = if tfIterator in t.flags: "iterator (" else: "proc ("
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
|
||||
add(result, t.n[i].sym.name.s)
|
||||
add(result, ": ")
|
||||
add(result, typeToString(t.sons[i]))
|
||||
if i < sonsLen(t) - 1: add(result, ", ")
|
||||
add(result, ')')
|
||||
|
||||
@@ -1043,7 +1043,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
decodeB(rkNode)
|
||||
let newLen = regs[rb].intVal.int
|
||||
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
|
||||
else: setLen(regs[ra].node.sons, newLen)
|
||||
else:
|
||||
let oldLen = regs[ra].node.len
|
||||
setLen(regs[ra].node.sons, newLen)
|
||||
if oldLen < newLen:
|
||||
# XXX This is still not entirely correct
|
||||
# set to default value:
|
||||
for i in oldLen .. <newLen:
|
||||
regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
|
||||
of opcSwap:
|
||||
let rb = instr.regB
|
||||
if regs[ra].kind == regs[rb].kind:
|
||||
|
||||
@@ -16,7 +16,7 @@ const
|
||||
byteExcess* = 128 # we use excess-K for immediates
|
||||
wordExcess* = 32768
|
||||
|
||||
MaxLoopIterations* = 500_000 # max iterations of all loops
|
||||
MaxLoopIterations* = 1500_000 # max iterations of all loops
|
||||
|
||||
|
||||
type
|
||||
@@ -29,7 +29,7 @@ type
|
||||
opcRet, # return
|
||||
opcYldYoid, # yield with no value
|
||||
opcYldVal, # yield with a value
|
||||
|
||||
|
||||
opcAsgnInt,
|
||||
opcAsgnStr,
|
||||
opcAsgnFloat,
|
||||
@@ -48,8 +48,8 @@ type
|
||||
opcWrDeref,
|
||||
opcWrStrIdx,
|
||||
opcLdStrIdx, # a = b[c]
|
||||
|
||||
opcAddInt,
|
||||
|
||||
opcAddInt,
|
||||
opcAddImmInt,
|
||||
opcSubInt,
|
||||
opcSubImmInt,
|
||||
@@ -58,36 +58,36 @@ type
|
||||
|
||||
opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
|
||||
opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
|
||||
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
|
||||
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
|
||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
|
||||
opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
|
||||
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
|
||||
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
|
||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
|
||||
opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
|
||||
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcSwap, opcIsNil, opcOf, opcIs,
|
||||
opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
|
||||
opcNarrowS, opcNarrowU,
|
||||
|
||||
|
||||
opcAddStrCh,
|
||||
opcAddStrStr,
|
||||
opcAddSeqElem,
|
||||
opcRangeChck,
|
||||
|
||||
|
||||
opcNAdd,
|
||||
opcNAddMultiple,
|
||||
opcNKind,
|
||||
opcNIntVal,
|
||||
opcNFloatVal,
|
||||
opcNSymbol,
|
||||
opcNKind,
|
||||
opcNIntVal,
|
||||
opcNFloatVal,
|
||||
opcNSymbol,
|
||||
opcNIdent,
|
||||
opcNGetType,
|
||||
opcNStrVal,
|
||||
|
||||
|
||||
opcNSetIntVal,
|
||||
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
|
||||
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
|
||||
|
||||
|
||||
opcSlurp,
|
||||
opcGorge,
|
||||
opcParseExprToAst,
|
||||
@@ -100,7 +100,7 @@ type
|
||||
opcEqIdent,
|
||||
opcStrToIdent,
|
||||
opcIdentToStr,
|
||||
|
||||
|
||||
opcEcho,
|
||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
@@ -110,7 +110,7 @@ type
|
||||
opcNSetChild,
|
||||
opcCallSite,
|
||||
opcNewStr,
|
||||
|
||||
|
||||
opcTJmp, # jump Bx if A != 0
|
||||
opcFJmp, # jump Bx if A == 0
|
||||
opcJmp, # jump Bx
|
||||
@@ -178,13 +178,13 @@ type
|
||||
slots*: pointer
|
||||
currentException*: PNode
|
||||
VmCallback* = proc (args: VmArgs) {.closure.}
|
||||
|
||||
|
||||
PCtx* = ref TCtx
|
||||
TCtx* = object of passes.TPassContext # code gen context
|
||||
code*: seq[TInstr]
|
||||
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
||||
# to not slow down interpretation
|
||||
globals*: PNode #
|
||||
globals*: PNode #
|
||||
constants*: PNode # constant data
|
||||
types*: seq[PType] # some instructions reference types (e.g. 'except')
|
||||
currentExceptionA*, currentExceptionB*: PNode
|
||||
@@ -203,7 +203,7 @@ type
|
||||
TPosition* = distinct int
|
||||
|
||||
PEvalContext* = PCtx
|
||||
|
||||
|
||||
proc newCtx*(module: PSym): PCtx =
|
||||
PCtx(code: @[], debug: @[],
|
||||
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
|
||||
|
||||
@@ -144,7 +144,9 @@ proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
|
||||
of tyIter: result = mapTypeToBracket("iter", t, info)
|
||||
of tyProxy: result = atomicType"error"
|
||||
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
|
||||
of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info)
|
||||
of tyUserTypeClass:
|
||||
result = mapTypeToBracket("concept", t, info)
|
||||
result.add t.n.copyTree
|
||||
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", t, info)
|
||||
|
||||
@@ -368,7 +368,7 @@ proc sameConstant*(a, b: PNode): bool =
|
||||
case a.kind
|
||||
of nkSym: result = a.sym == b.sym
|
||||
of nkIdent: result = a.ident.id == b.ident.id
|
||||
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
|
||||
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
|
||||
of nkType, nkNilLit: result = a.typ == b.typ
|
||||
@@ -742,9 +742,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.gABC(n, opcNewStr, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
# XXX buggy
|
||||
of mLengthOpenArray, mLengthArray, mLengthSeq:
|
||||
of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
|
||||
genUnaryABI(c, n, dest, opcLenSeq)
|
||||
of mLengthStr:
|
||||
of mLengthStr, mXLenStr:
|
||||
genUnaryABI(c, n, dest, opcLenStr)
|
||||
of mIncl, mExcl:
|
||||
unused(n, dest)
|
||||
@@ -791,7 +791,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
genUnaryABC(c, n, dest, opcUnaryMinusInt)
|
||||
genNarrow(c, n, dest)
|
||||
of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
|
||||
of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: gen(c, n.sons[1], dest)
|
||||
of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
|
||||
of mBitnotI, mBitnotI64:
|
||||
genUnaryABC(c, n, dest, opcBitnotInt)
|
||||
genNarrowU(c, n, dest)
|
||||
@@ -1008,7 +1008,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opcCallSite, dest)
|
||||
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
||||
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI,
|
||||
of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
|
||||
mAbsI64, mDotDot:
|
||||
c.genCall(n, dest)
|
||||
of mExpandToAst:
|
||||
@@ -1364,7 +1364,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
of tyCString, tyString:
|
||||
result = newNodeIT(nkStrLit, info, t)
|
||||
of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
|
||||
tyStmt, tyTypeDesc, tyStatic, tyRef:
|
||||
tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
|
||||
result = newNodeIT(nkNilLit, info, t)
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
@@ -1391,7 +1391,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
addSon(result, getNullValue(t.sons[i], info))
|
||||
of tySet:
|
||||
result = newNodeIT(nkCurly, info, t)
|
||||
else: internalError("getNullValue: " & $t.kind)
|
||||
else: internalError(info, "getNullValue: " & $t.kind)
|
||||
|
||||
proc ldNullOpcode(t: PType): TOpcode =
|
||||
if fitsRegister(t): opcLdNullReg else: opcLdNull
|
||||
@@ -1610,7 +1610,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
genBreak(c, n)
|
||||
of nkTryStmt: genTry(c, n, dest)
|
||||
of nkStmtList:
|
||||
unused(n, dest)
|
||||
#unused(n, dest)
|
||||
# XXX Fix this bug properly, lexim triggers it
|
||||
for x in n: gen(c, x)
|
||||
of nkStmtListExpr:
|
||||
let L = n.len-1
|
||||
|
||||
@@ -219,7 +219,7 @@ Concepts are written in the following form:
|
||||
(x < y) is bool
|
||||
|
||||
Container[T] = concept c
|
||||
c.len is ordinal
|
||||
c.len is Ordinal
|
||||
items(c) is iterator
|
||||
for value in c:
|
||||
type(value) is T
|
||||
|
||||
@@ -289,7 +289,7 @@ Numerical constants are of a single type and have the form::
|
||||
INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
|
||||
INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
|
||||
|
||||
UINT8_LIT = INT_LIT ['\''] ('u' | 'U')
|
||||
UINT_LIT = INT_LIT ['\''] ('u' | 'U')
|
||||
UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
|
||||
UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
|
||||
UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
|
||||
|
||||
@@ -71,10 +71,9 @@ procedural variable.
|
||||
|
||||
compileTime pragma
|
||||
------------------
|
||||
The ``compileTime`` pragma is used to mark a proc to be used at compile
|
||||
time only. No code will be generated for it. Compile time procs are useful
|
||||
as helpers for macros.
|
||||
|
||||
The ``compileTime`` pragma is used to mark a proc or variable to be used at
|
||||
compile time only. No code will be generated for it. Compile time procs are
|
||||
useful as helpers for macros.
|
||||
|
||||
noReturn pragma
|
||||
---------------
|
||||
|
||||
@@ -15,8 +15,6 @@ Associativity
|
||||
Binary operators whose first character is ``^`` are right-associative, all
|
||||
other binary operators are left-associative.
|
||||
|
||||
Operators ending in ``>`` but longer than a single character are
|
||||
called `arrow like`:idx:.
|
||||
|
||||
|
||||
Precedence
|
||||
@@ -33,9 +31,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
|
||||
For binary operators that are not keywords the precedence is determined by the
|
||||
following rules:
|
||||
|
||||
Operators ending in either ``->``, ``~>`` or ``=>`` are called
|
||||
`arrow like`:idx:, and have the lowest precedence of all operators.
|
||||
|
||||
If the operator ends with ``=`` and its first character is none of
|
||||
``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
|
||||
has the lowest precedence.
|
||||
has the second lowest precedence.
|
||||
|
||||
Otherwise precedence is determined by the first character.
|
||||
|
||||
@@ -43,14 +44,14 @@ Otherwise precedence is determined by the first character.
|
||||
Precedence level Operators First character Terminal symbol
|
||||
================ =============================================== ================== ===============
|
||||
10 (highest) ``$ ^`` OP10
|
||||
9 ``* / div mod shl shr %`` ``* % \ /`` OP9
|
||||
8 ``+ -`` ``+ ~ |`` OP8
|
||||
9 ``* / div mod shl shr %`` ``* % \ /`` OP9
|
||||
8 ``+ -`` ``+ - ~ |`` OP8
|
||||
7 ``&`` ``&`` OP7
|
||||
6 ``..`` ``.`` OP6
|
||||
5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5
|
||||
5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5
|
||||
4 ``and`` OP4
|
||||
3 ``or xor`` OP3
|
||||
2 ``@ : ?`` OP2
|
||||
2 ``@ : ?`` OP2
|
||||
1 *assignment operator* (like ``+=``, ``*=``) OP1
|
||||
0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0
|
||||
================ =============================================== ================== ===============
|
||||
@@ -67,7 +68,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
|
||||
|
||||
.. code-block:: nim
|
||||
#! strongSpaces
|
||||
if foo+4 * 4 == 8 and b&c | 9 ++
|
||||
if foo+4 * 4 == 8 and b&c | 9 ++
|
||||
bar:
|
||||
echo ""
|
||||
# is parsed as
|
||||
|
||||
@@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type.
|
||||
operator `=`
|
||||
------------
|
||||
|
||||
This operator is the assignment operator. Note that in the contexts
|
||||
like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for
|
||||
parameter passing no assignment is performed. The ``override`` pragma is
|
||||
optional for overriding ``=``.
|
||||
This operator is the assignment operator. Note that in the contexts
|
||||
``result = expr``, ``parameter = defaultValue`` or for
|
||||
parameter passing no assignment is performed. For a type ``T`` that has an
|
||||
overloaded assignment operator ``var v = T()`` is rewritten
|
||||
to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count
|
||||
as assignments.
|
||||
|
||||
The assignment operator needs to be attached to an object or distinct
|
||||
type ``T``. Its signature has to be ``(var T, T)``. Example:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Concrete = object
|
||||
a, b: string
|
||||
|
||||
proc `=`(d: var Concrete; src: Concrete) =
|
||||
shallowCopy(d.a, src.a)
|
||||
shallowCopy(d.b, src.b)
|
||||
echo "Concrete '=' called"
|
||||
|
||||
var x, y: array[0..2, Concrete]
|
||||
var cA, cB: Concrete
|
||||
|
||||
var cATup, cBTup: tuple[x: int, ha: Concrete]
|
||||
|
||||
x = y
|
||||
cA = cB
|
||||
cATup = cBTup
|
||||
|
||||
**Note**: Overriding of operator ``=`` is not yet implemented.
|
||||
|
||||
|
||||
destructors
|
||||
-----------
|
||||
|
||||
A destructor must have a single parameter with a concrete type (the name of a
|
||||
generic type is allowed too). The name of the destructor has to be ``destroy``
|
||||
and it need to be annotated with the ``override`` pragma.
|
||||
generic type is allowed too). The name of the destructor has to be ``=destroy``.
|
||||
|
||||
``destroy(v)`` will be automatically invoked for every local stack
|
||||
``=destroy(v)`` will be automatically invoked for every local stack
|
||||
variable ``v`` that goes out of scope.
|
||||
|
||||
If a structured type features a field with destructable type and
|
||||
If a structured type features a field with destructable type and
|
||||
the user has not provided an explicit implementation, a destructor for the
|
||||
structured type will be automatically generated. Calls to any base class
|
||||
structured type will be automatically generated. Calls to any base class
|
||||
destructors in both user-defined and generated destructors will be inserted.
|
||||
|
||||
A destructor is attached to the type it destructs; expressions of this type
|
||||
@@ -52,13 +74,13 @@ can then only be used in *destructible contexts* and as parameters:
|
||||
MyObj = object
|
||||
x, y: int
|
||||
p: pointer
|
||||
|
||||
proc destroy(o: var MyObj) {.override.} =
|
||||
|
||||
proc `=destroy`(o: var MyObj) =
|
||||
if o.p != nil: dealloc o.p
|
||||
|
||||
|
||||
proc open: MyObj =
|
||||
result = MyObj(x: 1, y: 2, p: alloc(3))
|
||||
|
||||
|
||||
proc work(o: MyObj) =
|
||||
echo o.x
|
||||
# No destructor invoked here for 'o' as 'o' is a parameter.
|
||||
@@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters:
|
||||
var x = open()
|
||||
# valid: pass 'x' to some other proc:
|
||||
work(x)
|
||||
|
||||
|
||||
# Error: usage of a type with a destructor in a non destructible context
|
||||
echo open()
|
||||
|
||||
@@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve
|
||||
the support of destructors.
|
||||
|
||||
Be aware that destructors are not called for objects allocated with ``new``.
|
||||
This may change in future versions of language, but for now the ``finalizer``
|
||||
This may change in future versions of language, but for now the `finalizer`:idx:
|
||||
parameter to ``new`` has to be used.
|
||||
|
||||
**Note**: Destructors are still experimental and the spec might change
|
||||
@@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis.
|
||||
deepCopy
|
||||
--------
|
||||
|
||||
``deepCopy`` is a builtin that is invoked whenever data is passed to
|
||||
``=deepCopy`` is a builtin that is invoked whenever data is passed to
|
||||
a ``spawn``'ed proc to ensure memory safety. The programmer can override its
|
||||
behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
|
||||
language may weaken this restriction.)
|
||||
@@ -103,10 +125,10 @@ language may weaken this restriction.)
|
||||
The signature has to be:
|
||||
|
||||
.. code-block:: nim
|
||||
proc deepCopy(x: T): T {.override.}
|
||||
proc `=deepCopy`(x: T): T
|
||||
|
||||
This mechanism is used by most data structures that support shared memory like
|
||||
channels to implement thread safe automatic memory management.
|
||||
This mechanism will be used by most data structures that support shared memory
|
||||
like channels to implement thread safe automatic memory management.
|
||||
|
||||
The builtin ``deepCopy`` can even clone closures and their environments. See
|
||||
the documentation of `spawn`_ for details.
|
||||
|
||||
@@ -864,7 +864,9 @@ Future directions:
|
||||
* Builtin regions like ``private``, ``global`` and ``local`` will
|
||||
prove very useful for the upcoming OpenCL target.
|
||||
* Builtin "regions" can model ``lent`` and ``unique`` pointers.
|
||||
|
||||
* An assignment operator can be attached to a region so that proper write
|
||||
barriers can be generated. This would imply that the GC can be implemented
|
||||
completely in user-space.
|
||||
|
||||
|
||||
Procedural type
|
||||
|
||||
21
doc/nimc.txt
21
doc/nimc.txt
@@ -506,7 +506,7 @@ For example:
|
||||
.. code-block:: nim
|
||||
|
||||
type Input {.importcpp: "System::Input".} = object
|
||||
proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()".}
|
||||
proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
|
||||
|
||||
let x: ptr Input = getSubsystem[Input]()
|
||||
|
||||
@@ -596,6 +596,25 @@ Produces:
|
||||
x[6] = 91.4;
|
||||
|
||||
|
||||
- If more precise control is needed, the apostrophe ``'`` can be used in the
|
||||
supplied pattern to denote the concrete type parameters of the generic type.
|
||||
See the usage of the apostrophe operator in proc patterns for more details.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
|
||||
|
||||
var x: VectorIterator[cint]
|
||||
|
||||
|
||||
Produces:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
std::vector<int>::iterator x;
|
||||
|
||||
|
||||
ImportObjC pragma
|
||||
-----------------
|
||||
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
||||
|
||||
49
koch.nim
49
koch.nim
@@ -81,7 +81,7 @@ proc exec(cmd: string, errorcode: int = QuitFailure) =
|
||||
echo(cmd)
|
||||
if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
|
||||
|
||||
proc tryExec(cmd: string): bool =
|
||||
proc tryExec(cmd: string): bool =
|
||||
echo(cmd)
|
||||
result = execShellCmd(cmd) == 0
|
||||
|
||||
@@ -96,7 +96,7 @@ proc copyExe(source, dest: string) =
|
||||
const
|
||||
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
|
||||
|
||||
proc csource(args: string) =
|
||||
proc csource(args: string) =
|
||||
exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" %
|
||||
[args, VersionAsString, compileNimInst, findNim()])
|
||||
|
||||
@@ -114,13 +114,13 @@ proc nsis(args: string) =
|
||||
# make sure we have generated the niminst executables:
|
||||
buildTool("tools/niminst/niminst", args)
|
||||
buildTool("tools/nimgrep", args)
|
||||
# produce 'nimrod_debug.exe':
|
||||
# produce 'nim_debug.exe':
|
||||
exec "nim c compiler" / "nim.nim"
|
||||
copyExe("compiler/nim".exe, "bin/nim_debug".exe)
|
||||
exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
|
||||
" nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
|
||||
|
||||
proc install(args: string) =
|
||||
proc install(args: string) =
|
||||
exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
|
||||
[findNim(), compileNimInst, VersionAsString])
|
||||
exec("sh ./install.sh $#" % args)
|
||||
@@ -139,12 +139,10 @@ proc pdf(args="") =
|
||||
|
||||
# -------------- boot ---------------------------------------------------------
|
||||
|
||||
proc findStartNim: string =
|
||||
proc findStartNim: string =
|
||||
# we try several things before giving up:
|
||||
# * bin/nim
|
||||
# * $PATH/nim
|
||||
# * bin/nimrod
|
||||
# * $PATH/nimrod
|
||||
# If these fail, we try to build nim with the "build.(sh|bat)" script.
|
||||
var nim = "nim".exe
|
||||
result = "bin" / nim
|
||||
@@ -152,34 +150,27 @@ proc findStartNim: string =
|
||||
for dir in split(getEnv("PATH"), PathSep):
|
||||
if existsFile(dir / nim): return dir / nim
|
||||
|
||||
# try the old "nimrod.exe":
|
||||
var nimrod = "nimrod".exe
|
||||
result = "bin" / nimrod
|
||||
if existsFile(result): return
|
||||
for dir in split(getEnv("PATH"), PathSep):
|
||||
if existsFile(dir / nim): return dir / nimrod
|
||||
|
||||
when defined(Posix):
|
||||
const buildScript = "build.sh"
|
||||
if existsFile(buildScript):
|
||||
if existsFile(buildScript):
|
||||
if tryExec("./" & buildScript): return "bin" / nim
|
||||
else:
|
||||
const buildScript = "build.bat"
|
||||
if existsFile(buildScript):
|
||||
if existsFile(buildScript):
|
||||
if tryExec(buildScript): return "bin" / nim
|
||||
|
||||
echo("Found no nim compiler and every attempt to build one failed!")
|
||||
quit("FAILURE")
|
||||
|
||||
proc thVersion(i: int): string =
|
||||
proc thVersion(i: int): string =
|
||||
result = ("compiler" / "nim" & $i).exe
|
||||
|
||||
|
||||
proc boot(args: string) =
|
||||
var output = "compiler" / "nim".exe
|
||||
var finalDest = "bin" / "nim".exe
|
||||
# default to use the 'c' command:
|
||||
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
|
||||
|
||||
|
||||
copyExe(findStartNim(), 0.thVersion)
|
||||
for i in 0..2:
|
||||
echo "iteration: ", i+1
|
||||
@@ -204,7 +195,7 @@ const
|
||||
".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
|
||||
]
|
||||
|
||||
proc cleanAux(dir: string) =
|
||||
proc cleanAux(dir: string) =
|
||||
for kind, path in walkDir(dir):
|
||||
case kind
|
||||
of pcFile:
|
||||
@@ -215,25 +206,25 @@ proc cleanAux(dir: string) =
|
||||
removeFile(path)
|
||||
of pcDir:
|
||||
case splitPath(path).tail
|
||||
of "nimcache":
|
||||
of "nimcache":
|
||||
echo "removing dir: ", path
|
||||
removeDir(path)
|
||||
of "dist", ".git", "icons": discard
|
||||
else: cleanAux(path)
|
||||
else: discard
|
||||
|
||||
proc removePattern(pattern: string) =
|
||||
for f in walkFiles(pattern):
|
||||
proc removePattern(pattern: string) =
|
||||
for f in walkFiles(pattern):
|
||||
echo "removing: ", f
|
||||
removeFile(f)
|
||||
|
||||
proc clean(args: string) =
|
||||
proc clean(args: string) =
|
||||
if existsFile("koch.dat"): removeFile("koch.dat")
|
||||
removePattern("web/*.html")
|
||||
removePattern("doc/*.html")
|
||||
cleanAux(getCurrentDir())
|
||||
for kind, path in walkDir(getCurrentDir() / "build"):
|
||||
if kind == pcDir:
|
||||
if kind == pcDir:
|
||||
echo "removing dir: ", path
|
||||
removeDir(path)
|
||||
|
||||
@@ -276,7 +267,7 @@ when defined(withUpdate):
|
||||
"Local branch must be ahead of it. Exiting...")
|
||||
else:
|
||||
quit("An error has occurred.")
|
||||
|
||||
|
||||
else:
|
||||
echo("No repo or executable found!")
|
||||
when defined(haveZipLib):
|
||||
@@ -293,7 +284,7 @@ when defined(withUpdate):
|
||||
quit("Error reading archive.")
|
||||
else:
|
||||
quit("No failback available. Exiting...")
|
||||
|
||||
|
||||
echo("Starting update...")
|
||||
boot(args)
|
||||
echo("Update complete!")
|
||||
@@ -346,8 +337,8 @@ proc temp(args: string) =
|
||||
copyExe(output, finalDest)
|
||||
if args.len > 0: exec(finalDest & " " & args)
|
||||
|
||||
proc showHelp() =
|
||||
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||
proc showHelp() =
|
||||
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||
CompileDate, CompileTime], QuitSuccess)
|
||||
|
||||
var op = initOptParser()
|
||||
|
||||
@@ -88,7 +88,9 @@ type
|
||||
ntyBigNum,
|
||||
ntyConst, ntyMutable, ntyVarargs,
|
||||
ntyIter,
|
||||
ntyError
|
||||
ntyError,
|
||||
ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
|
||||
ntyAnd, ntyOr, ntyNot
|
||||
|
||||
TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
|
||||
NimSymKind* = enum
|
||||
@@ -162,6 +164,7 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
|
||||
## returns the `kind` of the node `n`.
|
||||
|
||||
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
|
||||
proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
|
||||
proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
|
||||
proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
|
||||
proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
|
||||
@@ -355,6 +358,12 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} =
|
||||
## macros that check its number of arguments.
|
||||
if n.len != len: error("macro expects a node with " & $len & " children")
|
||||
|
||||
proc newTree*(kind: NimNodeKind,
|
||||
children: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new node with children.
|
||||
result = newNimNode(kind)
|
||||
result.add(children)
|
||||
|
||||
proc newCall*(theProc: NimNode,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
@@ -389,6 +398,11 @@ proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||
## produces a new boolean literal node.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = ord(b)
|
||||
|
||||
proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
|
||||
@@ -205,7 +205,7 @@ proc setEncoding*(connection: TDbConn, encoding: string): bool {.
|
||||
exec(connection, sql"PRAGMA encoding = ?", [encoding])
|
||||
result = connection.getValue(sql"PRAGMA encoding") == encoding
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var db = open("db.sql", "", "", "")
|
||||
exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
|
||||
exec(db, sql"insert into tbl1 values('hello!',10)", [])
|
||||
|
||||
@@ -499,7 +499,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
|
||||
if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
|
||||
if sdl_ttf.init() < 0: raiseEGraphics()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var surf = newScreenSurface(800, 600)
|
||||
|
||||
surf.fillSurface(colWhite)
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Regular expression support for Nim. Consider using the pegs module
|
||||
## instead.
|
||||
## Regular expression support for Nim. Consider using the pegs module instead.
|
||||
##
|
||||
## There is an alternative regular expressions library with a more unified API:
|
||||
## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard
|
||||
## library in the future, instead of `re`.
|
||||
##
|
||||
## **Note:** The 're' proc defaults to the **extended regular expression
|
||||
## syntax** which lets you use whitespace freely to make your regexes readable.
|
||||
@@ -36,31 +39,31 @@ const
|
||||
type
|
||||
RegexFlag* = enum ## options for regular expressions
|
||||
reIgnoreCase = 0, ## do caseless matching
|
||||
reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
|
||||
reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
|
||||
reDotAll = 2, ## ``.`` matches anything including NL
|
||||
reExtended = 3, ## ignore whitespace and ``#`` comments
|
||||
reStudy = 4 ## study the expression (may be omitted if the
|
||||
## expression will be used only once)
|
||||
|
||||
|
||||
RegexDesc = object
|
||||
h: PPcre
|
||||
e: ptr TExtra
|
||||
|
||||
h: ptr Pcre
|
||||
e: ptr ExtraData
|
||||
|
||||
Regex* = ref RegexDesc ## a compiled regular expression
|
||||
|
||||
|
||||
RegexError* = object of ValueError
|
||||
## is raised if the pattern is no valid regular expression.
|
||||
|
||||
{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
|
||||
EInvalidRegEx: RegexError].}
|
||||
|
||||
proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
|
||||
proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
|
||||
var e: ref RegexError
|
||||
new(e)
|
||||
e.msg = msg
|
||||
raise e
|
||||
|
||||
proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||
proc rawCompile(pattern: string, flags: cint): ptr Pcre =
|
||||
var
|
||||
msg: cstring
|
||||
offset: cint
|
||||
@@ -68,10 +71,10 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||
if result == nil:
|
||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
|
||||
|
||||
proc finalizeRegEx(x: Regex) =
|
||||
proc finalizeRegEx(x: Regex) =
|
||||
# XXX This is a hack, but PCRE does not export its "free" function properly.
|
||||
# Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
|
||||
# Fortunately the implementation is unlikely to change.
|
||||
# Fortunately the implementation is unlikely to change.
|
||||
pcre.free_substring(cast[cstring](x.h))
|
||||
if not isNil(x.e):
|
||||
pcre.free_substring(cast[cstring](x.e))
|
||||
@@ -84,7 +87,7 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
|
||||
result.h = rawCompile(s, cast[cint](flags - {reStudy}))
|
||||
if reStudy in flags:
|
||||
var msg: cstring
|
||||
result.e = pcre.study(result.h, 0, msg)
|
||||
result.e = pcre.study(result.h, 0, addr msg)
|
||||
if not isNil(msg): raiseInvalidRegex($msg)
|
||||
|
||||
proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
|
||||
@@ -101,10 +104,10 @@ proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
|
||||
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
|
||||
else: matches[i-1] = nil
|
||||
return rawMatches[1] - rawMatches[0]
|
||||
|
||||
|
||||
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
|
||||
start = 0): tuple[first, last: int] =
|
||||
## returns the starting position and end position of `pattern` in `s`
|
||||
## returns the starting position and end position of `pattern` in `s`
|
||||
## and the captured
|
||||
## substrings in the array `matches`. If it does not match, nothing
|
||||
## is written into `matches` and ``(-1,0)`` is returned.
|
||||
@@ -120,12 +123,12 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
|
||||
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
|
||||
else: matches[i-1] = nil
|
||||
return (rawMatches[0].int, rawMatches[1].int - 1)
|
||||
|
||||
proc findBounds*(s: string, pattern: Regex,
|
||||
|
||||
proc findBounds*(s: string, pattern: Regex,
|
||||
matches: var openArray[tuple[first, last: int]],
|
||||
start = 0): tuple[first, last: int] =
|
||||
## returns the starting position and end position of ``pattern`` in ``s``
|
||||
## and the captured substrings in the array `matches`.
|
||||
## returns the starting position and end position of ``pattern`` in ``s``
|
||||
## and the captured substrings in the array `matches`.
|
||||
## If it does not match, nothing is written into `matches` and
|
||||
## ``(-1,0)`` is returned.
|
||||
var
|
||||
@@ -141,7 +144,7 @@ proc findBounds*(s: string, pattern: Regex,
|
||||
else: matches[i-1] = (-1,0)
|
||||
return (rawMatches[0].int, rawMatches[1].int - 1)
|
||||
|
||||
proc findBounds*(s: string, pattern: Regex,
|
||||
proc findBounds*(s: string, pattern: Regex,
|
||||
start = 0): tuple[first, last: int] =
|
||||
## returns the starting position of `pattern` in `s`. If it does not
|
||||
## match, ``(-1,0)`` is returned.
|
||||
@@ -152,7 +155,7 @@ proc findBounds*(s: string, pattern: Regex,
|
||||
cast[ptr cint](rawMatches), 3)
|
||||
if res < 0'i32: return (int(res), 0)
|
||||
return (int(rawMatches[0]), int(rawMatches[1]-1))
|
||||
|
||||
|
||||
proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint =
|
||||
var
|
||||
rtarray = initRtArray[cint](3)
|
||||
@@ -172,7 +175,7 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
|
||||
proc matchLen*(s: string, pattern: Regex, start = 0): int =
|
||||
## the same as ``match``, but it returns the length of the match,
|
||||
## if there is no match, -1 is returned. Note that a match length
|
||||
## of zero can happen.
|
||||
## of zero can happen.
|
||||
return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
|
||||
|
||||
proc match*(s: string, pattern: Regex, start = 0): bool =
|
||||
@@ -216,7 +219,7 @@ proc find*(s: string, pattern: Regex, start = 0): int =
|
||||
if res < 0'i32: return res
|
||||
return rawMatches[0]
|
||||
|
||||
iterator findAll*(s: string, pattern: Regex, start = 0): string =
|
||||
iterator findAll*(s: string, pattern: Regex, start = 0): string =
|
||||
## Yields all matching *substrings* of `s` that match `pattern`.
|
||||
##
|
||||
## Note that since this is an iterator you should not modify the string you
|
||||
@@ -231,10 +234,11 @@ iterator findAll*(s: string, pattern: Regex, start = 0): string =
|
||||
if res < 0'i32: break
|
||||
let a = rawMatches[0]
|
||||
let b = rawMatches[1]
|
||||
if a == b and a == i: break
|
||||
yield substr(s, int(a), int(b)-1)
|
||||
i = b
|
||||
|
||||
proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
|
||||
proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
|
||||
## returns all matching *substrings* of `s` that match `pattern`.
|
||||
## If it does not match, @[] is returned.
|
||||
accumulateResult(findAll(s, pattern, start))
|
||||
@@ -242,13 +246,13 @@ proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
template `=~` *(s: string, pattern: Regex): expr =
|
||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||
## can be used in the scope of the ``=~`` call:
|
||||
##
|
||||
template `=~` *(s: string, pattern: Regex): expr =
|
||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||
## can be used in the scope of the ``=~`` call:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
|
||||
## if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
|
||||
## # matches a key=value pair:
|
||||
## echo("Key: ", matches[0])
|
||||
## echo("Value: ", matches[1])
|
||||
@@ -260,9 +264,9 @@ template `=~` *(s: string, pattern: Regex): expr =
|
||||
## else:
|
||||
## echo("syntax error")
|
||||
##
|
||||
bind MaxSubPatterns
|
||||
bind MaxSubpatterns
|
||||
when not declaredInScope(matches):
|
||||
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
||||
var matches {.inject.}: array[MaxSubpatterns, string]
|
||||
match(s, pattern, matches)
|
||||
|
||||
# ------------------------- more string handling ------------------------------
|
||||
@@ -286,7 +290,7 @@ proc endsWith*(s: string, suffix: Regex): bool =
|
||||
if matchLen(s, suffix, i) == s.len - i: return true
|
||||
|
||||
proc replace*(s: string, sub: Regex, by = ""): string =
|
||||
## Replaces `sub` in `s` by the string `by`. Captures cannot be
|
||||
## Replaces `sub` in `s` by the string `by`. Captures cannot be
|
||||
## accessed in `by`. Examples:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
@@ -306,7 +310,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
|
||||
add(result, by)
|
||||
prev = match.last + 1
|
||||
add(result, substr(s, prev))
|
||||
|
||||
|
||||
proc replacef*(s: string, sub: Regex, by: string): string =
|
||||
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
|
||||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||
@@ -320,7 +324,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
||||
##
|
||||
## "var1<-keykey; val2<-key2key2"
|
||||
result = ""
|
||||
var caps: array[0..MaxSubpatterns-1, string]
|
||||
var caps: array[MaxSubpatterns, string]
|
||||
var prev = 0
|
||||
while true:
|
||||
var match = findBounds(s, sub, caps, prev)
|
||||
@@ -338,7 +342,7 @@ proc parallelReplace*(s: string, subs: openArray[
|
||||
## applied in parallel.
|
||||
result = ""
|
||||
var i = 0
|
||||
var caps: array[0..MaxSubpatterns-1, string]
|
||||
var caps: array[MaxSubpatterns, string]
|
||||
while i < s.len:
|
||||
block searchSubs:
|
||||
for j in 0..high(subs):
|
||||
@@ -359,7 +363,7 @@ proc transformFile*(infile, outfile: string,
|
||||
## error occurs. This is supposed to be used for quick scripting.
|
||||
var x = readFile(infile).string
|
||||
writeFile(outfile, x.parallelReplace(subs))
|
||||
|
||||
|
||||
iterator split*(s: string, sep: Regex): string =
|
||||
## Splits the string `s` into substrings.
|
||||
##
|
||||
@@ -373,64 +377,73 @@ iterator split*(s: string, sep: Regex): string =
|
||||
## Results in:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## ""
|
||||
## "this"
|
||||
## "is"
|
||||
## "an"
|
||||
## "example"
|
||||
## ""
|
||||
##
|
||||
var
|
||||
first = 0
|
||||
last = 0
|
||||
first = -1
|
||||
last = -1
|
||||
while last < len(s):
|
||||
var x = matchLen(s, sep, last)
|
||||
if x > 0: inc(last, x)
|
||||
first = last
|
||||
if x == 0: inc(last)
|
||||
while last < len(s):
|
||||
inc(last)
|
||||
x = matchLen(s, sep, last)
|
||||
if x > 0: break
|
||||
if first < last:
|
||||
if x >= 0: break
|
||||
inc(last)
|
||||
if first <= last:
|
||||
yield substr(s, first, last-1)
|
||||
|
||||
proc split*(s: string, sep: Regex): seq[string] =
|
||||
## Splits the string `s` into substrings.
|
||||
accumulateResult(split(s, sep))
|
||||
|
||||
proc escapeRe*(s: string): string =
|
||||
## escapes `s` so that it is matched verbatim when used as a regular
|
||||
|
||||
proc escapeRe*(s: string): string =
|
||||
## escapes `s` so that it is matched verbatim when used as a regular
|
||||
## expression.
|
||||
result = ""
|
||||
for c in items(s):
|
||||
case c
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_':
|
||||
result.add(c)
|
||||
else:
|
||||
else:
|
||||
result.add("\\x")
|
||||
result.add(toHex(ord(c), 2))
|
||||
|
||||
|
||||
const ## common regular expressions
|
||||
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reNatural* = r"\b\d+\b" ## describes a natural number
|
||||
reInteger* = r"\b[-+]?\d+\b" ## describes an integer
|
||||
reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
|
||||
reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
|
||||
reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
|
||||
reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
|
||||
reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
|
||||
## describes an identifier
|
||||
reNatural* {.deprecated.} = r"\b\d+\b"
|
||||
## describes a natural number
|
||||
reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
|
||||
## describes an integer
|
||||
reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
|
||||
## describes a hexadecimal number
|
||||
reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
|
||||
## describes a binary number (example: 0b11101)
|
||||
reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
|
||||
## describes an octal number (example: 0o777)
|
||||
reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
|
||||
## describes a floating point number
|
||||
reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
|
||||
r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
|
||||
r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
|
||||
r"(?:[a-zA-Z]{2}|com|org|" &
|
||||
r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
|
||||
reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
|
||||
r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
|
||||
r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
|
||||
r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
|
||||
r"info|mobi|name|aero|jobs|museum)\b"
|
||||
## describes a common email address
|
||||
reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
|
||||
r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
|
||||
reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
|
||||
r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
|
||||
## describes an URL
|
||||
|
||||
when isMainModule:
|
||||
assert match("(a b c)", re"\( .* \)")
|
||||
assert match("WHiLe", re("while", {reIgnoreCase}))
|
||||
|
||||
|
||||
assert "0158787".match(re"\d+")
|
||||
assert "ABC 0232".match(re"\w+\s+\d+")
|
||||
assert "ABC".match(re"\d+ | \w+")
|
||||
@@ -439,21 +452,21 @@ when isMainModule:
|
||||
|
||||
var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
|
||||
assert matchLen("key1= cal9", pattern) == 11
|
||||
|
||||
|
||||
assert find("_____abc_______", re"abc") == 5
|
||||
|
||||
var matches: array[0..5, string]
|
||||
if match("abcdefg", re"c(d)ef(g)", matches, 2):
|
||||
|
||||
var matches: array[6, string]
|
||||
if match("abcdefg", re"c(d)ef(g)", matches, 2):
|
||||
assert matches[0] == "d"
|
||||
assert matches[1] == "g"
|
||||
else:
|
||||
assert false
|
||||
|
||||
|
||||
if "abc" =~ re"(a)bcxyz|(\w+)":
|
||||
assert matches[1] == "abc"
|
||||
else:
|
||||
assert false
|
||||
|
||||
|
||||
if "abc" =~ re"(cba)?.*":
|
||||
assert matches[0] == nil
|
||||
else: assert false
|
||||
@@ -461,7 +474,7 @@ when isMainModule:
|
||||
if "abc" =~ re"().*":
|
||||
assert matches[0] == ""
|
||||
else: assert false
|
||||
|
||||
|
||||
assert "var1=key; var2=key2".endsWith(re"\w+=\w+")
|
||||
assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
|
||||
"var1<-keykey; var2<-key2key2")
|
||||
@@ -471,7 +484,12 @@ when isMainModule:
|
||||
var accum: seq[string] = @[]
|
||||
for word in split("00232this02939is39an22example111", re"\d+"):
|
||||
accum.add(word)
|
||||
assert(accum == @["this", "is", "an", "example"])
|
||||
assert(accum == @["", "this", "is", "an", "example", ""])
|
||||
|
||||
accum = @[]
|
||||
for word in split("AAA : : BBB", re"\s*:\s*"):
|
||||
accum.add(word)
|
||||
assert(accum == @["AAA", "", "BBB"])
|
||||
|
||||
for x in findAll("abcdef", re"^{.}", 3):
|
||||
assert x == "d"
|
||||
@@ -484,7 +502,7 @@ when isMainModule:
|
||||
assert("XYZ".match(re"^\d*") == true)
|
||||
|
||||
block:
|
||||
var matches: array[0..15, string]
|
||||
var matches: array[16, string]
|
||||
if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
|
||||
for i in 0..matches.high:
|
||||
assert matches[i] == $chr(i + 'a'.ord)
|
||||
|
||||
@@ -82,7 +82,7 @@ proc close*(sock: TSecureSocket) =
|
||||
ERR_print_errors_fp(stderr)
|
||||
raiseOSError(osLastError())
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var s: TSecureSocket
|
||||
echo connect(s, "smtp.gmail.com", 465)
|
||||
|
||||
|
||||
293
lib/js/dom.nim
293
lib/js/dom.nim
@@ -36,8 +36,11 @@ type
|
||||
onsubmit*: proc (event: ref TEvent) {.nimcall.}
|
||||
onunload*: proc (event: ref TEvent) {.nimcall.}
|
||||
|
||||
TWindow* {.importc.} = object of TEventHandlers
|
||||
document*: ref TDocument
|
||||
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
|
||||
|
||||
Window* = ref WindowObj
|
||||
WindowObj {.importc.} = object of TEventHandlers
|
||||
document*: Document
|
||||
event*: ref TEvent
|
||||
history*: ref THistory
|
||||
location*: ref TLocation
|
||||
@@ -55,7 +58,6 @@ type
|
||||
status*: cstring
|
||||
toolbar*: ref TToolBar
|
||||
|
||||
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
|
||||
alert*: proc (msg: cstring) {.nimcall.}
|
||||
back*: proc () {.nimcall.}
|
||||
blur*: proc () {.nimcall.}
|
||||
@@ -66,7 +68,7 @@ type
|
||||
confirm*: proc (msg: cstring): bool {.nimcall.}
|
||||
disableExternalCapture*: proc () {.nimcall.}
|
||||
enableExternalCapture*: proc () {.nimcall.}
|
||||
find*: proc (text: cstring, caseSensitive = false,
|
||||
find*: proc (text: cstring, caseSensitive = false,
|
||||
backwards = false) {.nimcall.}
|
||||
focus*: proc () {.nimcall.}
|
||||
forward*: proc () {.nimcall.}
|
||||
@@ -75,7 +77,7 @@ type
|
||||
moveBy*: proc (x, y: int) {.nimcall.}
|
||||
moveTo*: proc (x, y: int) {.nimcall.}
|
||||
open*: proc (uri, windowname: cstring,
|
||||
properties: cstring = nil): ref TWindow {.nimcall.}
|
||||
properties: cstring = nil): Window {.nimcall.}
|
||||
print*: proc () {.nimcall.}
|
||||
prompt*: proc (text, default: cstring): cstring {.nimcall.}
|
||||
releaseEvents*: proc (eventMask: int) {.nimcall.}
|
||||
@@ -89,115 +91,8 @@ type
|
||||
stop*: proc () {.nimcall.}
|
||||
frames*: seq[TFrame]
|
||||
|
||||
TFrame* {.importc.} = object of TWindow
|
||||
|
||||
TDocument* {.importc.} = object of TEventHandlers
|
||||
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
|
||||
alinkColor*: cstring
|
||||
bgColor*: cstring
|
||||
charset*: cstring
|
||||
cookie*: cstring
|
||||
defaultCharset*: cstring
|
||||
fgColor*: cstring
|
||||
lastModified*: cstring
|
||||
linkColor*: cstring
|
||||
referrer*: cstring
|
||||
title*: cstring
|
||||
URL*: cstring
|
||||
vlinkColor*: cstring
|
||||
captureEvents*: proc (eventMask: int) {.nimcall.}
|
||||
createAttribute*: proc (identifier: cstring): ref TNode {.nimcall.}
|
||||
createElement*: proc (identifier: cstring): ref TNode {.nimcall.}
|
||||
createTextNode*: proc (identifier: cstring): ref TNode {.nimcall.}
|
||||
getElementById*: proc (id: cstring): ref TNode {.nimcall.}
|
||||
getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
||||
getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
||||
getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
||||
getSelection*: proc (): cstring {.nimcall.}
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
open*: proc () {.nimcall.}
|
||||
releaseEvents*: proc (eventMask: int) {.nimcall.}
|
||||
routeEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
write*: proc (text: cstring) {.nimcall.}
|
||||
writeln*: proc (text: cstring) {.nimcall.}
|
||||
anchors*: seq[ref TAnchor]
|
||||
forms*: seq[ref TForm]
|
||||
images*: seq[ref TImage]
|
||||
applets*: seq[ref TApplet]
|
||||
embeds*: seq[ref TEmbed]
|
||||
links*: seq[ref TLink]
|
||||
|
||||
TLink* {.importc.} = object of RootObj
|
||||
name*: cstring
|
||||
target*: cstring
|
||||
text*: cstring
|
||||
x*: int
|
||||
y*: int
|
||||
|
||||
TEmbed* {.importc.} = object of RootObj
|
||||
height*: int
|
||||
hspace*: int
|
||||
name*: cstring
|
||||
src*: cstring
|
||||
width*: int
|
||||
`type`*: cstring
|
||||
vspace*: int
|
||||
play*: proc () {.nimcall.}
|
||||
stop*: proc () {.nimcall.}
|
||||
|
||||
TAnchor* {.importc.} = object of RootObj
|
||||
name*: cstring
|
||||
text*: cstring
|
||||
x*, y*: int
|
||||
|
||||
TApplet* {.importc.} = object of RootObj
|
||||
|
||||
TElement* {.importc.} = object of TEventHandlers
|
||||
checked*: bool
|
||||
defaultChecked*: bool
|
||||
defaultValue*: cstring
|
||||
disabled*: bool
|
||||
form*: ref TForm
|
||||
name*: cstring
|
||||
readOnly*: bool
|
||||
`type`*: cstring
|
||||
value*: cstring
|
||||
blur*: proc () {.nimcall.}
|
||||
click*: proc () {.nimcall.}
|
||||
focus*: proc () {.nimcall.}
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
select*: proc () {.nimcall.}
|
||||
options*: seq[ref TOption]
|
||||
|
||||
TOption* {.importc.} = object of RootObj
|
||||
defaultSelected*: bool
|
||||
selected*: bool
|
||||
selectedIndex*: int
|
||||
text*: cstring
|
||||
value*: cstring
|
||||
|
||||
TForm* {.importc.} = object of TEventHandlers
|
||||
action*: cstring
|
||||
encoding*: cstring
|
||||
`method`*: cstring
|
||||
name*: cstring
|
||||
target*: cstring
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
reset*: proc () {.nimcall.}
|
||||
submit*: proc () {.nimcall.}
|
||||
elements*: seq[ref TElement]
|
||||
|
||||
TImage* {.importc.} = object of TEventHandlers
|
||||
border*: int
|
||||
complete*: bool
|
||||
height*: int
|
||||
hspace*: int
|
||||
lowsrc*: cstring
|
||||
name*: cstring
|
||||
src*: cstring
|
||||
vspace*: int
|
||||
width*: int
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
Frame* = ref FrameObj
|
||||
FrameObj {.importc.} = object of WindowObj
|
||||
|
||||
ClassList* {.importc.} = object of RootObj
|
||||
add*: proc (class: cstring) {.nimcall.}
|
||||
@@ -218,43 +113,151 @@ type
|
||||
DocumentTypeNode,
|
||||
DocumentFragmentNode,
|
||||
NotationNode
|
||||
TNode* {.importc.} = object of RootObj
|
||||
attributes*: seq[ref TNode]
|
||||
childNodes*: seq[ref TNode]
|
||||
children*: seq[ref TNode]
|
||||
classList*: ref Classlist
|
||||
|
||||
Node* = ref NodeObj
|
||||
NodeObj {.importc.} = object of TEventHandlers
|
||||
attributes*: seq[Node]
|
||||
childNodes*: seq[Node]
|
||||
children*: seq[Node]
|
||||
data*: cstring
|
||||
firstChild*: ref TNode
|
||||
lastChild*: ref TNode
|
||||
nextSibling*: ref TNode
|
||||
firstChild*: Node
|
||||
lastChild*: Node
|
||||
nextSibling*: Node
|
||||
nodeName*: cstring
|
||||
nodeType*: TNodeType
|
||||
nodeValue*: cstring
|
||||
parentNode*: ref TNode
|
||||
previousSibling*: ref TNode
|
||||
appendChild*: proc (child: ref TNode) {.nimcall.}
|
||||
parentNode*: Node
|
||||
previousSibling*: Node
|
||||
appendChild*: proc (child: Node) {.nimcall.}
|
||||
appendData*: proc (data: cstring) {.nimcall.}
|
||||
cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.}
|
||||
cloneNode*: proc (copyContent: bool): Node {.nimcall.}
|
||||
deleteData*: proc (start, len: int) {.nimcall.}
|
||||
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
|
||||
getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
|
||||
getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
||||
getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
|
||||
getAttributeNode*: proc (attr: cstring): Node {.nimcall.}
|
||||
hasChildNodes*: proc (): bool {.nimcall.}
|
||||
innerHTML*: cstring
|
||||
insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
|
||||
insertBefore*: proc (newNode, before: Node) {.nimcall.}
|
||||
insertData*: proc (position: int, data: cstring) {.nimcall.}
|
||||
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent)) {.nimcall.}
|
||||
removeAttribute*: proc (attr: cstring) {.nimcall.}
|
||||
removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
|
||||
removeChild*: proc (child: ref TNode) {.nimcall.}
|
||||
replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
|
||||
removeAttributeNode*: proc (attr: Node) {.nimcall.}
|
||||
removeChild*: proc (child: Node) {.nimcall.}
|
||||
replaceChild*: proc (newNode, oldNode: Node) {.nimcall.}
|
||||
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
|
||||
scrollIntoView*: proc () {.nimcall.}
|
||||
setAttribute*: proc (name, value: cstring) {.nimcall.}
|
||||
setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
|
||||
setAttributeNode*: proc (attr: Node) {.nimcall.}
|
||||
style*: ref TStyle
|
||||
|
||||
Document* = ref DocumentObj
|
||||
DocumentObj {.importc.} = object of NodeObj
|
||||
alinkColor*: cstring
|
||||
bgColor*: cstring
|
||||
charset*: cstring
|
||||
cookie*: cstring
|
||||
defaultCharset*: cstring
|
||||
fgColor*: cstring
|
||||
lastModified*: cstring
|
||||
linkColor*: cstring
|
||||
referrer*: cstring
|
||||
title*: cstring
|
||||
URL*: cstring
|
||||
vlinkColor*: cstring
|
||||
captureEvents*: proc (eventMask: int) {.nimcall.}
|
||||
createAttribute*: proc (identifier: cstring): Node {.nimcall.}
|
||||
createElement*: proc (identifier: cstring): Element {.nimcall.}
|
||||
createTextNode*: proc (identifier: cstring): Node {.nimcall.}
|
||||
getElementById*: proc (id: cstring): Element {.nimcall.}
|
||||
getElementsByName*: proc (name: cstring): seq[Element] {.nimcall.}
|
||||
getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
|
||||
getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
|
||||
getSelection*: proc (): cstring {.nimcall.}
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
open*: proc () {.nimcall.}
|
||||
releaseEvents*: proc (eventMask: int) {.nimcall.}
|
||||
routeEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
write*: proc (text: cstring) {.nimcall.}
|
||||
writeln*: proc (text: cstring) {.nimcall.}
|
||||
anchors*: seq[AnchorElement]
|
||||
forms*: seq[FormElement]
|
||||
images*: seq[ImageElement]
|
||||
applets*: seq[ref TApplet]
|
||||
embeds*: seq[EmbedElement]
|
||||
links*: seq[LinkElement]
|
||||
|
||||
Element* = ref ElementObj
|
||||
ElementObj {.importc.} = object of NodeObj
|
||||
classList*: ref Classlist
|
||||
checked*: bool
|
||||
defaultChecked*: bool
|
||||
defaultValue*: cstring
|
||||
disabled*: bool
|
||||
form*: FormElement
|
||||
name*: cstring
|
||||
readOnly*: bool
|
||||
blur*: proc () {.nimcall.}
|
||||
click*: proc () {.nimcall.}
|
||||
focus*: proc () {.nimcall.}
|
||||
handleEvent*: proc (event: ref TEvent) {.nimcall.}
|
||||
select*: proc () {.nimcall.}
|
||||
options*: seq[OptionElement]
|
||||
getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
|
||||
getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
|
||||
|
||||
LinkElement* = ref LinkObj
|
||||
LinkObj {.importc.} = object of ElementObj
|
||||
target*: cstring
|
||||
text*: cstring
|
||||
x*: int
|
||||
y*: int
|
||||
|
||||
EmbedElement* = ref EmbedObj
|
||||
EmbedObj {.importc.} = object of ElementObj
|
||||
height*: int
|
||||
hspace*: int
|
||||
src*: cstring
|
||||
width*: int
|
||||
`type`*: cstring
|
||||
vspace*: int
|
||||
play*: proc () {.nimcall.}
|
||||
stop*: proc () {.nimcall.}
|
||||
|
||||
AnchorElement* = ref AnchorObj
|
||||
AnchorObj {.importc.} = object of ElementObj
|
||||
text*: cstring
|
||||
x*, y*: int
|
||||
|
||||
TApplet* {.importc.} = object of RootObj
|
||||
|
||||
OptionElement* = ref OptionObj
|
||||
OptionObj {.importc.} = object of ElementObj
|
||||
defaultSelected*: bool
|
||||
selected*: bool
|
||||
selectedIndex*: int
|
||||
text*: cstring
|
||||
value*: cstring
|
||||
|
||||
FormElement* = ref FormObj
|
||||
FormObj {.importc.} = object of ElementObj
|
||||
action*: cstring
|
||||
encoding*: cstring
|
||||
`method`*: cstring
|
||||
target*: cstring
|
||||
reset*: proc () {.nimcall.}
|
||||
submit*: proc () {.nimcall.}
|
||||
elements*: seq[Element]
|
||||
|
||||
ImageElement* = ref ImageObj
|
||||
ImageObj {.importc.} = object of ElementObj
|
||||
border*: int
|
||||
complete*: bool
|
||||
height*: int
|
||||
hspace*: int
|
||||
lowsrc*: cstring
|
||||
src*: cstring
|
||||
vspace*: int
|
||||
width*: int
|
||||
|
||||
|
||||
TStyle* {.importc.} = object of RootObj
|
||||
background*: cstring
|
||||
backgroundAttachment*: cstring
|
||||
@@ -350,7 +353,7 @@ type
|
||||
setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.}
|
||||
|
||||
TEvent* {.importc.} = object of RootObj
|
||||
target*: ref TNode
|
||||
target*: Node
|
||||
altKey*, ctrlKey*, shiftKey*: bool
|
||||
button*: int
|
||||
clientX*, clientY*: int
|
||||
@@ -448,8 +451,8 @@ type
|
||||
TInterval* {.importc.} = object of RootObj
|
||||
|
||||
var
|
||||
window* {.importc, nodecl.}: ref TWindow
|
||||
document* {.importc, nodecl.}: ref TDocument
|
||||
window* {.importc, nodecl.}: Window
|
||||
document* {.importc, nodecl.}: Document
|
||||
navigator* {.importc, nodecl.}: ref TNavigator
|
||||
screen* {.importc, nodecl.}: ref TScreen
|
||||
|
||||
@@ -466,3 +469,17 @@ proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
|
||||
proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
|
||||
proc parseInt*(s: cstring): int {.importc, nodecl.}
|
||||
proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
|
||||
|
||||
|
||||
type
|
||||
TWindow* {.deprecated.} = WindowObj
|
||||
TFrame* {.deprecated.} = FrameObj
|
||||
TNode* {.deprecated.} = NodeObj
|
||||
TDocument* {.deprecated.} = DocumentObj
|
||||
TElement* {.deprecated.} = ElementObj
|
||||
TLink* {.deprecated.} = LinkObj
|
||||
TEmbed* {.deprecated.} = EmbedObj
|
||||
TAnchor* {.deprecated.} = AnchorObj
|
||||
TOption* {.deprecated.} = OptionObj
|
||||
TForm* {.deprecated.} = FormObj
|
||||
TImage* {.deprecated.} = ImageObj
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ type
|
||||
rnField, # a field item
|
||||
rnFieldName, # consisting of a field name ...
|
||||
rnFieldBody, # ... and a field body
|
||||
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
|
||||
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
|
||||
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
|
||||
rnLineBlock, # the | thingie
|
||||
rnLineBlockItem, # sons of the | thing
|
||||
@@ -50,7 +50,7 @@ type
|
||||
# * `file#id <file#id>'_
|
||||
rnSubstitutionDef, # a definition of a substitution
|
||||
rnGeneralRole, # Inline markup:
|
||||
rnSub, rnSup, rnIdx,
|
||||
rnSub, rnSup, rnIdx,
|
||||
rnEmphasis, # "*"
|
||||
rnStrongEmphasis, # "**"
|
||||
rnTripleEmphasis, # "***"
|
||||
@@ -71,25 +71,25 @@ type
|
||||
level*: int ## valid for some node kinds
|
||||
sons*: TRstNodeSeq ## the node's sons
|
||||
|
||||
proc len*(n: PRstNode): int =
|
||||
proc len*(n: PRstNode): int =
|
||||
result = len(n.sons)
|
||||
|
||||
proc newRstNode*(kind: TRstNodeKind): PRstNode =
|
||||
proc newRstNode*(kind: TRstNodeKind): PRstNode =
|
||||
new(result)
|
||||
result.sons = @[]
|
||||
result.kind = kind
|
||||
|
||||
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
|
||||
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
|
||||
result = newRstNode(kind)
|
||||
result.text = s
|
||||
|
||||
proc lastSon*(n: PRstNode): PRstNode =
|
||||
proc lastSon*(n: PRstNode): PRstNode =
|
||||
result = n.sons[len(n.sons)-1]
|
||||
|
||||
proc add*(father, son: PRstNode) =
|
||||
add(father.sons, son)
|
||||
|
||||
proc addIfNotNil*(father, son: PRstNode) =
|
||||
proc addIfNotNil*(father, son: PRstNode) =
|
||||
if son != nil: add(father, son)
|
||||
|
||||
|
||||
@@ -98,26 +98,27 @@ type
|
||||
indent: int
|
||||
verbatim: int
|
||||
|
||||
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string)
|
||||
proc renderRstToRst(d: var TRenderContext, n: PRstNode,
|
||||
result: var string) {.gcsafe.}
|
||||
|
||||
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
for i in countup(0, len(n) - 1):
|
||||
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
for i in countup(0, len(n) - 1):
|
||||
renderRstToRst(d, n.sons[i], result)
|
||||
|
||||
|
||||
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
# this is needed for the index generation; it may also be useful for
|
||||
# debugging, but most code is already debugged...
|
||||
const
|
||||
const
|
||||
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
||||
if n == nil: return
|
||||
var ind = spaces(d.indent)
|
||||
case n.kind
|
||||
of rnInner:
|
||||
of rnInner:
|
||||
renderRstSons(d, n, result)
|
||||
of rnHeadline:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
|
||||
|
||||
let oldLen = result.len
|
||||
renderRstSons(d, n, result)
|
||||
let headlineLen = result.len - oldLen
|
||||
@@ -131,16 +132,16 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
|
||||
var headline = ""
|
||||
renderRstSons(d, n, headline)
|
||||
|
||||
|
||||
let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
|
||||
result.add(lvl)
|
||||
result.add("\n")
|
||||
result.add(headline)
|
||||
|
||||
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add(lvl)
|
||||
of rnTransition:
|
||||
of rnTransition:
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
result.add repeat('-', 78-d.indent)
|
||||
@@ -149,11 +150,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
renderRstSons(d, n, result)
|
||||
of rnBulletItem:
|
||||
of rnBulletItem:
|
||||
inc(d.indent, 2)
|
||||
var tmp = ""
|
||||
renderRstSons(d, n, tmp)
|
||||
if tmp.len > 0:
|
||||
if tmp.len > 0:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add("* ")
|
||||
@@ -163,22 +164,22 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
inc(d.indent, 4)
|
||||
var tmp = ""
|
||||
renderRstSons(d, n, tmp)
|
||||
if tmp.len > 0:
|
||||
if tmp.len > 0:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add("(#) ")
|
||||
result.add(tmp)
|
||||
dec(d.indent, 4)
|
||||
of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
|
||||
rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
|
||||
of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
|
||||
rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
|
||||
renderRstSons(d, n, result)
|
||||
of rnDefName:
|
||||
of rnDefName:
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
renderRstSons(d, n, result)
|
||||
of rnDefBody:
|
||||
inc(d.indent, 2)
|
||||
if n.sons[0].kind != rnBulletList:
|
||||
if n.sons[0].kind != rnBulletList:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add(" ")
|
||||
@@ -187,10 +188,10 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
of rnField:
|
||||
var tmp = ""
|
||||
renderRstToRst(d, n.sons[0], tmp)
|
||||
|
||||
|
||||
var L = max(tmp.len + 3, 30)
|
||||
inc(d.indent, L)
|
||||
|
||||
|
||||
result.add "\n"
|
||||
result.add ind
|
||||
result.add ':'
|
||||
@@ -198,9 +199,9 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add ':'
|
||||
result.add spaces(L - tmp.len - 2)
|
||||
renderRstToRst(d, n.sons[1], result)
|
||||
|
||||
|
||||
dec(d.indent, L)
|
||||
of rnLineBlockItem:
|
||||
of rnLineBlockItem:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add("| ")
|
||||
@@ -209,11 +210,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
inc(d.indent, 2)
|
||||
renderRstSons(d, n, result)
|
||||
dec(d.indent, 2)
|
||||
of rnRef:
|
||||
of rnRef:
|
||||
result.add("`")
|
||||
renderRstSons(d, n, result)
|
||||
result.add("`_")
|
||||
of rnHyperlink:
|
||||
of rnHyperlink:
|
||||
result.add('`')
|
||||
renderRstToRst(d, n.sons[0], result)
|
||||
result.add(" <")
|
||||
@@ -225,23 +226,23 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add("`:")
|
||||
renderRstToRst(d, n.sons[1],result)
|
||||
result.add(':')
|
||||
of rnSub:
|
||||
of rnSub:
|
||||
result.add('`')
|
||||
renderRstSons(d, n, result)
|
||||
result.add("`:sub:")
|
||||
of rnSup:
|
||||
of rnSup:
|
||||
result.add('`')
|
||||
renderRstSons(d, n, result)
|
||||
result.add("`:sup:")
|
||||
of rnIdx:
|
||||
of rnIdx:
|
||||
result.add('`')
|
||||
renderRstSons(d, n, result)
|
||||
result.add("`:idx:")
|
||||
of rnEmphasis:
|
||||
of rnEmphasis:
|
||||
result.add("*")
|
||||
renderRstSons(d, n, result)
|
||||
result.add("*")
|
||||
of rnStrongEmphasis:
|
||||
of rnStrongEmphasis:
|
||||
result.add("**")
|
||||
renderRstSons(d, n, result)
|
||||
result.add("**")
|
||||
@@ -249,11 +250,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add("***")
|
||||
renderRstSons(d, n, result)
|
||||
result.add("***")
|
||||
of rnInterpretedText:
|
||||
of rnInterpretedText:
|
||||
result.add('`')
|
||||
renderRstSons(d, n, result)
|
||||
result.add('`')
|
||||
of rnInlineLiteral:
|
||||
of rnInlineLiteral:
|
||||
inc(d.verbatim)
|
||||
result.add("``")
|
||||
renderRstSons(d, n, result)
|
||||
@@ -266,11 +267,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add("\\\\") # XXX: escape more special characters!
|
||||
else:
|
||||
result.add(n.text)
|
||||
of rnIndex:
|
||||
of rnIndex:
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
result.add(".. index::\n")
|
||||
|
||||
|
||||
inc(d.indent, 3)
|
||||
if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
|
||||
dec(d.indent, 3)
|
||||
@@ -280,7 +281,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||
result.add(".. contents::")
|
||||
else:
|
||||
result.add("Error: cannot render: " & $n.kind)
|
||||
|
||||
|
||||
proc renderRstToRst*(n: PRstNode, result: var string) =
|
||||
## renders `n` into its string representation and appends to `result`.
|
||||
var d: TRenderContext
|
||||
@@ -302,7 +303,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
|
||||
|
||||
proc renderRstToJson*(node: PRstNode): string =
|
||||
## Writes the given RST node as JSON that is in the form
|
||||
## ::
|
||||
## ::
|
||||
## {
|
||||
## "kind":string node.kind,
|
||||
## "text":optional string node.text,
|
||||
|
||||
@@ -34,14 +34,14 @@ type
|
||||
TOutputTarget* = enum ## which document type to generate
|
||||
outHtml, # output is HTML
|
||||
outLatex # output is Latex
|
||||
|
||||
TTocEntry = object
|
||||
|
||||
TTocEntry = object
|
||||
n*: PRstNode
|
||||
refname*, header*: string
|
||||
|
||||
TMetaEnum* = enum
|
||||
TMetaEnum* = enum
|
||||
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
||||
|
||||
|
||||
TRstGenerator* = object of RootObj
|
||||
target*: TOutputTarget
|
||||
config*: StringTableRef
|
||||
@@ -60,7 +60,7 @@ type
|
||||
seenIndexTerms: Table[string, int] ## \
|
||||
## Keeps count of same text index terms to generate different identifiers
|
||||
## for hyperlinks. See renderIndexTerm proc for details.
|
||||
|
||||
|
||||
PDoc = var TRstGenerator ## Alias to type less.
|
||||
|
||||
CodeBlockParams = object ## Stores code block params.
|
||||
@@ -136,7 +136,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
|
||||
g.currentSection = "Module " & fileParts.name
|
||||
g.seenIndexTerms = initTable[string, int]()
|
||||
g.msgHandler = msgHandler
|
||||
|
||||
|
||||
let s = config["split.item.toc"]
|
||||
if s != "": g.splitAfter = parseInt(s)
|
||||
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
||||
@@ -147,23 +147,23 @@ proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
|
||||
## You previously need to add entries to the index with the `setIndexTerm()
|
||||
## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
|
||||
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
|
||||
|
||||
proc addXmlChar(dest: var string, c: char) =
|
||||
|
||||
proc addXmlChar(dest: var string, c: char) =
|
||||
case c
|
||||
of '&': add(dest, "&")
|
||||
of '<': add(dest, "<")
|
||||
of '>': add(dest, ">")
|
||||
of '\"': add(dest, """)
|
||||
else: add(dest, c)
|
||||
|
||||
proc addRtfChar(dest: var string, c: char) =
|
||||
|
||||
proc addRtfChar(dest: var string, c: char) =
|
||||
case c
|
||||
of '{': add(dest, "\\{")
|
||||
of '}': add(dest, "\\}")
|
||||
of '\\': add(dest, "\\\\")
|
||||
else: add(dest, c)
|
||||
|
||||
proc addTexChar(dest: var string, c: char) =
|
||||
|
||||
proc addTexChar(dest: var string, c: char) =
|
||||
case c
|
||||
of '_': add(dest, "\\_")
|
||||
of '{': add(dest, "\\symbol{123}")
|
||||
@@ -183,54 +183,54 @@ proc addTexChar(dest: var string, c: char) =
|
||||
|
||||
var splitter*: string = "<wbr />"
|
||||
|
||||
proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
|
||||
proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
|
||||
case target
|
||||
of outHtml: addXmlChar(dest, c)
|
||||
of outLatex: addTexChar(dest, c)
|
||||
|
||||
proc nextSplitPoint*(s: string, start: int): int =
|
||||
|
||||
proc nextSplitPoint*(s: string, start: int): int =
|
||||
result = start
|
||||
while result < len(s) + 0:
|
||||
while result < len(s) + 0:
|
||||
case s[result]
|
||||
of '_': return
|
||||
of 'a'..'z':
|
||||
if result + 1 < len(s) + 0:
|
||||
if s[result + 1] in {'A'..'Z'}: return
|
||||
of '_': return
|
||||
of 'a'..'z':
|
||||
if result + 1 < len(s) + 0:
|
||||
if s[result + 1] in {'A'..'Z'}: return
|
||||
else: discard
|
||||
inc(result)
|
||||
dec(result) # last valid index
|
||||
|
||||
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
|
||||
|
||||
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
|
||||
result = ""
|
||||
if splitAfter >= 0:
|
||||
if splitAfter >= 0:
|
||||
var partLen = 0
|
||||
var j = 0
|
||||
while j < len(s):
|
||||
while j < len(s):
|
||||
var k = nextSplitPoint(s, j)
|
||||
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
|
||||
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
|
||||
partLen = 0
|
||||
add(result, splitter)
|
||||
for i in countup(j, k): escChar(target, result, s[i])
|
||||
inc(partLen, k - j + 1)
|
||||
j = k + 1
|
||||
else:
|
||||
else:
|
||||
for i in countup(0, len(s) - 1): escChar(target, result, s[i])
|
||||
|
||||
|
||||
proc disp(target: TOutputTarget, xml, tex: string): string =
|
||||
if target != outLatex: result = xml
|
||||
if target != outLatex: result = xml
|
||||
else: result = tex
|
||||
|
||||
proc dispF(target: TOutputTarget, xml, tex: string,
|
||||
args: varargs[string]): string =
|
||||
if target != outLatex: result = xml % args
|
||||
|
||||
proc dispF(target: TOutputTarget, xml, tex: string,
|
||||
args: varargs[string]): string =
|
||||
if target != outLatex: result = xml % args
|
||||
else: result = tex % args
|
||||
|
||||
proc dispA(target: TOutputTarget, dest: var string,
|
||||
|
||||
proc dispA(target: TOutputTarget, dest: var string,
|
||||
xml, tex: string, args: varargs[string]) =
|
||||
if target != outLatex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
|
||||
proc `or`(x, y: string): string {.inline.} =
|
||||
result = if x.isNil: y else: x
|
||||
|
||||
@@ -248,7 +248,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
|
||||
## renderRstToOut(gen, rst, generatedHTML)
|
||||
## echo generatedHTML
|
||||
|
||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
|
||||
|
||||
proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
|
||||
@@ -347,7 +347,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
var term = ""
|
||||
renderAux(d, n, term)
|
||||
setIndexTerm(d, id, term, d.currentSection)
|
||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
|
||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
|
||||
[id, term])
|
||||
|
||||
type
|
||||
@@ -656,7 +656,7 @@ proc mergeIndexes*(dir: string): string =
|
||||
result.add("<h2>API symbols</h2>\n")
|
||||
result.add(generateSymbolIndex(symbols))
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc stripTOCHTML(s: string): string =
|
||||
@@ -677,7 +677,7 @@ proc stripTOCHTML(s: string): string =
|
||||
result.delete(first, last)
|
||||
first = result.find('<', first)
|
||||
|
||||
proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||
d.currentSection = tmp
|
||||
@@ -700,9 +700,9 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
"id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
|
||||
[$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
|
||||
else:
|
||||
dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
|
||||
dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
|
||||
"\\rsth$4{$3}\\label{$2}\n", [
|
||||
$n.level, refname, tmp,
|
||||
$n.level, refname, tmp,
|
||||
$chr(n.level - 1 + ord('A'))])
|
||||
|
||||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||
@@ -710,7 +710,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
||||
spaces(max(0, n.level)) & tmp)
|
||||
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
if d.meta[metaTitle].len == 0:
|
||||
for i in countup(0, len(n)-1):
|
||||
renderRstToOut(d, n.sons[i], d.meta[metaTitle])
|
||||
@@ -723,14 +723,14 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||
d.currentSection = tmp
|
||||
dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
|
||||
dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
|
||||
"\\rstov$4{$3}\\label{$2}\n", [$n.level,
|
||||
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
|
||||
|
||||
|
||||
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
|
||||
|
||||
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
|
||||
|
||||
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
|
||||
@@ -759,33 +759,33 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||
var options = ""
|
||||
var s = getFieldValue(n, "scale")
|
||||
if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "height")
|
||||
if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "width")
|
||||
if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "alt")
|
||||
if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "align")
|
||||
if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
|
||||
|
||||
|
||||
if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
|
||||
|
||||
let arg = getArgument(n)
|
||||
if arg.valid:
|
||||
dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
|
||||
dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
|
||||
[arg, options])
|
||||
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
|
||||
|
||||
|
||||
proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"""<img src="$1" width="15"
|
||||
"""<img src="$1" width="15"
|
||||
height="17" hspace="2" vspace="2" class="smiley" />""",
|
||||
"\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
|
||||
|
||||
|
||||
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
|
||||
## Parses useful fields which can appear before a code block.
|
||||
##
|
||||
@@ -880,11 +880,11 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||
else:
|
||||
var g: TGeneralTokenizer
|
||||
initGeneralTokenizer(g, m.text)
|
||||
while true:
|
||||
while true:
|
||||
getNextToken(g, params.lang)
|
||||
case g.kind
|
||||
of gtEof: break
|
||||
of gtNone, gtWhitespace:
|
||||
of gtEof: break
|
||||
of gtNone, gtWhitespace:
|
||||
add(result, substr(m.text, g.start, g.length + g.start - 1))
|
||||
else:
|
||||
dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
|
||||
@@ -893,36 +893,36 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||
deinitGeneralTokenizer(g)
|
||||
dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
|
||||
|
||||
proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
renderRstToOut(d, n.sons[2], tmp)
|
||||
var arg = strip(getArgument(n))
|
||||
if arg == "":
|
||||
if arg == "":
|
||||
dispA(d.target, result, "<div>$1</div>", "$1", [tmp])
|
||||
else:
|
||||
dispA(d.target, result, "<div class=\"$1\">$2</div>", "$2", [arg, tmp])
|
||||
|
||||
proc texColumns(n: PRstNode): string =
|
||||
|
||||
proc texColumns(n: PRstNode): string =
|
||||
result = ""
|
||||
for i in countup(1, len(n)): add(result, "|X")
|
||||
|
||||
proc renderField(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
proc renderField(d: PDoc, n: PRstNode, result: var string) =
|
||||
var b = false
|
||||
if d.target == outLatex:
|
||||
if d.target == outLatex:
|
||||
var fieldname = addNodes(n.sons[0])
|
||||
var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
|
||||
if cmpIgnoreStyle(fieldname, "author") == 0 or
|
||||
if cmpIgnoreStyle(fieldname, "author") == 0 or
|
||||
cmpIgnoreStyle(fieldname, "authors") == 0:
|
||||
if d.meta[metaAuthor].len == 0:
|
||||
d.meta[metaAuthor] = fieldval
|
||||
b = true
|
||||
elif cmpIgnoreStyle(fieldname, "version") == 0:
|
||||
elif cmpIgnoreStyle(fieldname, "version") == 0:
|
||||
if d.meta[metaVersion].len == 0:
|
||||
d.meta[metaVersion] = fieldval
|
||||
b = true
|
||||
if not b:
|
||||
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
||||
|
||||
|
||||
proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
@@ -947,54 +947,54 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
|
||||
of rnFieldList:
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1):
|
||||
for i in countup(0, len(n) - 1):
|
||||
renderRstToOut(d, n.sons[i], tmp)
|
||||
if tmp.len != 0:
|
||||
if tmp.len != 0:
|
||||
dispA(d.target, result,
|
||||
"<table class=\"docinfo\" frame=\"void\" rules=\"none\">" &
|
||||
"<col class=\"docinfo-name\" />" &
|
||||
"<col class=\"docinfo-content\" />" &
|
||||
"<col class=\"docinfo-content\" />" &
|
||||
"<tbody valign=\"top\">$1" &
|
||||
"</tbody></table>",
|
||||
"\\begin{description}$1\\end{description}\n",
|
||||
"</tbody></table>",
|
||||
"\\begin{description}$1\\end{description}\n",
|
||||
[tmp])
|
||||
of rnField: renderField(d, n, result)
|
||||
of rnFieldName:
|
||||
of rnFieldName:
|
||||
renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
|
||||
"\\item[$1:]", result)
|
||||
of rnFieldBody:
|
||||
of rnFieldBody:
|
||||
renderAux(d, n, "<td>$1</td>", " $1\n", result)
|
||||
of rnIndex:
|
||||
of rnIndex:
|
||||
renderRstToOut(d, n.sons[2], result)
|
||||
of rnOptionList:
|
||||
renderAux(d, n, "<table frame=\"void\">$1</table>",
|
||||
of rnOptionList:
|
||||
renderAux(d, n, "<table frame=\"void\">$1</table>",
|
||||
"\\begin{description}\n$1\\end{description}\n", result)
|
||||
of rnOptionListItem:
|
||||
of rnOptionListItem:
|
||||
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
||||
of rnOptionGroup:
|
||||
of rnOptionGroup:
|
||||
renderAux(d, n, "<th align=\"left\">$1</th>", "\\item[$1]", result)
|
||||
of rnDescription:
|
||||
of rnDescription:
|
||||
renderAux(d, n, "<td align=\"left\">$1</td>\n", " $1\n", result)
|
||||
of rnOption, rnOptionString, rnOptionArgument:
|
||||
of rnOption, rnOptionString, rnOptionArgument:
|
||||
doAssert false, "renderRstToOut"
|
||||
of rnLiteralBlock:
|
||||
renderAux(d, n, "<pre>$1</pre>\n",
|
||||
renderAux(d, n, "<pre>$1</pre>\n",
|
||||
"\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
|
||||
of rnQuotedLiteralBlock:
|
||||
of rnQuotedLiteralBlock:
|
||||
doAssert false, "renderRstToOut"
|
||||
of rnLineBlock:
|
||||
of rnLineBlock:
|
||||
renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
|
||||
of rnLineBlockItem:
|
||||
of rnLineBlockItem:
|
||||
renderAux(d, n, "$1<br />", "$1\\\\\n", result)
|
||||
of rnBlockQuote:
|
||||
renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
|
||||
of rnBlockQuote:
|
||||
renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
|
||||
"\\begin{quote}$1\\end{quote}\n", result)
|
||||
of rnTable, rnGridTable:
|
||||
renderAux(d, n,
|
||||
"<table border=\"1\" class=\"docutils\">$1</table>",
|
||||
of rnTable, rnGridTable:
|
||||
renderAux(d, n,
|
||||
"<table border=\"1\" class=\"docutils\">$1</table>",
|
||||
"\\begin{table}\\begin{rsttab}{" &
|
||||
texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
|
||||
of rnTableRow:
|
||||
of rnTableRow:
|
||||
if len(n) >= 1:
|
||||
if d.target == outLatex:
|
||||
#var tmp = ""
|
||||
@@ -1007,25 +1007,25 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
result.add("<tr>")
|
||||
renderAux(d, n, result)
|
||||
result.add("</tr>\n")
|
||||
of rnTableDataCell:
|
||||
of rnTableDataCell:
|
||||
renderAux(d, n, "<td>$1</td>", "$1", result)
|
||||
of rnTableHeaderCell:
|
||||
of rnTableHeaderCell:
|
||||
renderAux(d, n, "<th>$1</th>", "\\textbf{$1}", result)
|
||||
of rnLabel:
|
||||
of rnLabel:
|
||||
doAssert false, "renderRstToOut" # used for footnotes and other
|
||||
of rnFootnote:
|
||||
of rnFootnote:
|
||||
doAssert false, "renderRstToOut" # a footnote
|
||||
of rnCitation:
|
||||
of rnCitation:
|
||||
doAssert false, "renderRstToOut" # similar to footnote
|
||||
of rnRef:
|
||||
of rnRef:
|
||||
var tmp = ""
|
||||
renderAux(d, n, tmp)
|
||||
dispA(d.target, result,
|
||||
"<a class=\"reference external\" href=\"#$2\">$1</a>",
|
||||
"$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
|
||||
of rnStandaloneHyperlink:
|
||||
renderAux(d, n,
|
||||
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
||||
of rnStandaloneHyperlink:
|
||||
renderAux(d, n,
|
||||
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
||||
"\\href{$1}{$1}", result)
|
||||
of rnHyperlink:
|
||||
var tmp0 = ""
|
||||
@@ -1042,11 +1042,11 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
of rnRawLatex:
|
||||
if d.target == outLatex:
|
||||
result.add addNodes(lastSon(n))
|
||||
|
||||
|
||||
of rnImage, rnFigure: renderImage(d, n, result)
|
||||
of rnCodeBlock: renderCodeBlock(d, n, result)
|
||||
of rnContainer: renderContainer(d, n, result)
|
||||
of rnSubstitutionReferences, rnSubstitutionDef:
|
||||
of rnSubstitutionReferences, rnSubstitutionDef:
|
||||
renderAux(d, n, "|$1|", "|$1|", result)
|
||||
of rnDirective:
|
||||
renderAux(d, n, "", "", result)
|
||||
@@ -1063,15 +1063,15 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
of rnStrongEmphasis:
|
||||
renderAux(d, n, "<strong>$1</strong>", "\\textbf{$1}", result)
|
||||
of rnTripleEmphasis:
|
||||
renderAux(d, n, "<strong><em>$1</em></strong>",
|
||||
renderAux(d, n, "<strong><em>$1</em></strong>",
|
||||
"\\textbf{emph{$1}}", result)
|
||||
of rnInterpretedText:
|
||||
renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
|
||||
of rnIdx:
|
||||
renderIndexTerm(d, n, result)
|
||||
of rnInlineLiteral:
|
||||
renderAux(d, n,
|
||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||
of rnInlineLiteral:
|
||||
renderAux(d, n,
|
||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||
"\\texttt{$1}", result)
|
||||
of rnSmiley: renderSmiley(d, n, result)
|
||||
of rnLeaf: result.add(esc(d.target, n.text))
|
||||
@@ -1082,55 +1082,55 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
return i
|
||||
result = -1
|
||||
|
||||
proc formatNamedVars*(frmt: string, varnames: openArray[string],
|
||||
varvalues: openArray[string]): string =
|
||||
proc formatNamedVars*(frmt: string, varnames: openArray[string],
|
||||
varvalues: openArray[string]): string =
|
||||
var i = 0
|
||||
var L = len(frmt)
|
||||
result = ""
|
||||
var num = 0
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '#':
|
||||
of '#':
|
||||
add(result, varvalues[num])
|
||||
inc(num)
|
||||
inc(i)
|
||||
of '$':
|
||||
of '$':
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
while true:
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if i > L-1 or frmt[i] notin {'0'..'9'}: break
|
||||
if i > L-1 or frmt[i] notin {'0'..'9'}: break
|
||||
if j > high(varvalues) + 1:
|
||||
raise newException(ValueError, "invalid index: " & $j)
|
||||
num = j
|
||||
add(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
var id = ""
|
||||
while true:
|
||||
while true:
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
|
||||
if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0:
|
||||
if idx >= 0:
|
||||
add(result, varvalues[idx])
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution var: " & id)
|
||||
of '{':
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0':
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0':
|
||||
raise newException(ValueError, "'}' expected")
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
@@ -1138,12 +1138,12 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
|
||||
# search for the variable:
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else:
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution var: " & id)
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution: $" & $frmt[i])
|
||||
var start = i
|
||||
while i < L:
|
||||
while i < L:
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i-1 >= start: add(result, substr(frmt, start, i - 1))
|
||||
@@ -1163,10 +1163,10 @@ proc defaultConfig*(): StringTableRef =
|
||||
## pages, while this proc returns just the content for procs like
|
||||
## ``rstToHtml`` to generate the bare minimum HTML.
|
||||
result = newStringTable(modeStyleInsensitive)
|
||||
|
||||
|
||||
template setConfigVar(key, val: expr) =
|
||||
result[key] = val
|
||||
|
||||
|
||||
# If you need to modify these values, it might be worth updating the template
|
||||
# file in config/nimdoc.cfg.
|
||||
setConfigVar("split.item.toc", "20")
|
||||
@@ -1214,7 +1214,7 @@ $content
|
||||
|
||||
# ---------- forum ---------------------------------------------------------
|
||||
|
||||
proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
config: StringTableRef): string =
|
||||
## Converts an input rst string into embeddable HTML.
|
||||
##
|
||||
@@ -1236,13 +1236,13 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
## output you have to create your own ``TRstGenerator`` with
|
||||
## ``initRstGenerator`` and related procs.
|
||||
|
||||
proc myFindFile(filename: string): string =
|
||||
proc myFindFile(filename: string): string =
|
||||
# we don't find any files in online mode:
|
||||
result = ""
|
||||
|
||||
const filen = "input"
|
||||
var d: TRstGenerator
|
||||
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
|
||||
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
|
||||
rst.defaultMsgHandler)
|
||||
var dummyHasToc = false
|
||||
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
|
||||
@@ -1251,5 +1251,6 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
|
||||
|
||||
when isMainModule:
|
||||
echo rstToHtml("*Hello* **world**!", {},
|
||||
newStringTable(modeStyleInsensitive))
|
||||
assert rstToHtml("*Hello* **world**!", {},
|
||||
newStringTable(modeStyleInsensitive)) ==
|
||||
"<em>Hello</em> <strong>world</strong>!"
|
||||
|
||||
@@ -95,10 +95,11 @@ type
|
||||
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
||||
d_ino*: Tino ## File serial number.
|
||||
when defined(linux) or defined(macosx) or defined(bsd):
|
||||
d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
|
||||
d_reclen*: cshort ## Length of this record. (not POSIX)
|
||||
d_type*: int8 ## Type of file; not supported by all filesystem types.
|
||||
## (not POSIX)
|
||||
when defined(linux) or defined(bsd):
|
||||
d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
|
||||
d_name*: array [0..255, char] ## Name of entry.
|
||||
|
||||
Tflock* {.importc: "struct flock", final, pure,
|
||||
@@ -1579,8 +1580,11 @@ else:
|
||||
|
||||
when defined(macosx):
|
||||
# We can't use the NOSIGNAL flag in the ``send`` function, it has no effect
|
||||
var
|
||||
# Instead we should use SO_NOSIGPIPE in setsockopt
|
||||
const
|
||||
MSG_NOSIGNAL* = 0'i32
|
||||
var
|
||||
SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
|
||||
else:
|
||||
var
|
||||
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
|
||||
|
||||
@@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
|
||||
setupTask()
|
||||
schedule()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var
|
||||
a: TActorPool[int, void]
|
||||
createActorPool(a)
|
||||
|
||||
@@ -24,7 +24,7 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||
var y = order.ord - 1
|
||||
result = (x xor y) - y
|
||||
|
||||
proc reverse*[T](a: var openArray[T], first, last: int) =
|
||||
proc reverse*[T](a: var openArray[T], first, last: Natural) =
|
||||
## reverses the array ``a[first..last]``.
|
||||
var x = first
|
||||
var y = last
|
||||
@@ -37,11 +37,11 @@ proc reverse*[T](a: var openArray[T]) =
|
||||
## reverses the array `a`.
|
||||
reverse(a, 0, a.high)
|
||||
|
||||
proc reversed*[T](a: openArray[T], first, last: int): seq[T] =
|
||||
proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
|
||||
## returns the reverse of the array `a[first..last]`.
|
||||
result = newSeq[T](last - first + 1)
|
||||
var x = first
|
||||
var y = last
|
||||
var x = first.int
|
||||
var y = last.int
|
||||
while x <= last:
|
||||
result[x] = a[y]
|
||||
dec(y)
|
||||
|
||||
@@ -841,6 +841,8 @@ else:
|
||||
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
|
||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
when defined(macosx):
|
||||
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
|
||||
register(result)
|
||||
|
||||
proc newAsyncRawSocket*(domain: Domain = AF_INET,
|
||||
@@ -848,6 +850,8 @@ else:
|
||||
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
|
||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
when defined(macosx):
|
||||
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
|
||||
register(result)
|
||||
|
||||
proc closeSocket*(sock: TAsyncFD) =
|
||||
@@ -959,7 +963,6 @@ else:
|
||||
result = true
|
||||
let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
|
||||
flags.toOSFlags())
|
||||
#echo("recv cb res: ", res)
|
||||
if res < 0:
|
||||
let lastError = osLastError()
|
||||
if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
|
||||
|
||||
@@ -300,7 +300,7 @@ proc newAsyncFtpClient*(address: string, port = Port(21),
|
||||
result.dsockConnected = false
|
||||
result.csock = newAsyncSocket()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
|
||||
proc main(ftp: AsyncFtpClient) {.async.} =
|
||||
await ftp.connect()
|
||||
|
||||
@@ -260,7 +260,7 @@ proc close*(server: AsyncHttpServer) =
|
||||
## Terminates the async http server instance.
|
||||
server.socket.close()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
var server = newAsyncHttpServer()
|
||||
proc cb(req: Request) {.async.} =
|
||||
|
||||
@@ -660,7 +660,7 @@ proc len*(disp: Dispatcher): int =
|
||||
## Retrieves the amount of delegates in ``disp``.
|
||||
return disp.delegates.len
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
|
||||
proc testConnect(s: AsyncSocket, no: int) =
|
||||
echo("Connected! " & $no)
|
||||
|
||||
@@ -458,7 +458,7 @@ proc isClosed*(socket: AsyncSocket): bool =
|
||||
## Determines whether the socket has been closed.
|
||||
return socket.closed
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
type
|
||||
TestCases = enum
|
||||
HighClient, LowClient, LowServer
|
||||
|
||||
@@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
|
||||
|
||||
|
||||
#Tests ----------------------------
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import locks, times, mersenne
|
||||
|
||||
const
|
||||
|
||||
@@ -286,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
|
||||
result.add("}")
|
||||
|
||||
when isMainModule:
|
||||
import sequtils
|
||||
|
||||
var r: CritBitTree[void]
|
||||
r.incl "abc"
|
||||
r.incl "xyz"
|
||||
r.incl "def"
|
||||
r.incl "definition"
|
||||
r.incl "prefix"
|
||||
|
||||
doAssert r.contains"def"
|
||||
#r.del "def"
|
||||
|
||||
for w in r.items:
|
||||
echo w
|
||||
|
||||
for w in r.itemsWithPrefix("de"):
|
||||
echo w
|
||||
r.excl "def"
|
||||
|
||||
assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
|
||||
|
||||
assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
## copy; use ``assign`` to get a deep copy.
|
||||
|
||||
import
|
||||
os, hashes, math
|
||||
hashes, math
|
||||
|
||||
type
|
||||
BitScalar = int
|
||||
|
||||
const
|
||||
const
|
||||
InitIntSetSize = 8 # must be a power of two!
|
||||
TrunkShift = 9
|
||||
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
|
||||
@@ -31,11 +31,11 @@ const
|
||||
|
||||
type
|
||||
PTrunk = ref TTrunk
|
||||
TTrunk {.final.} = object
|
||||
TTrunk {.final.} = object
|
||||
next: PTrunk # all nodes are connected with this pointer
|
||||
key: int # start address at bit 0
|
||||
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
|
||||
|
||||
|
||||
TTrunkSeq = seq[PTrunk]
|
||||
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
|
||||
counter, max: int
|
||||
@@ -44,42 +44,42 @@ type
|
||||
|
||||
{.deprecated: [TIntSet: IntSet].}
|
||||
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
|
||||
proc intSetGet(t: IntSet, key: int): PTrunk =
|
||||
proc intSetGet(t: IntSet, key: int): PTrunk =
|
||||
var h = key and t.max
|
||||
while t.data[h] != nil:
|
||||
if t.data[h].key == key:
|
||||
while t.data[h] != nil:
|
||||
if t.data[h].key == key:
|
||||
return t.data[h]
|
||||
h = nextTry(h, t.max)
|
||||
result = nil
|
||||
|
||||
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
|
||||
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
|
||||
var h = desc.key and t.max
|
||||
while data[h] != nil:
|
||||
while data[h] != nil:
|
||||
assert(data[h] != desc)
|
||||
h = nextTry(h, t.max)
|
||||
assert(data[h] == nil)
|
||||
data[h] = desc
|
||||
|
||||
proc intSetEnlarge(t: var IntSet) =
|
||||
proc intSetEnlarge(t: var IntSet) =
|
||||
var n: TTrunkSeq
|
||||
var oldMax = t.max
|
||||
t.max = ((t.max + 1) * 2) - 1
|
||||
newSeq(n, t.max + 1)
|
||||
for i in countup(0, oldMax):
|
||||
for i in countup(0, oldMax):
|
||||
if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
|
||||
swap(t.data, n)
|
||||
|
||||
proc intSetPut(t: var IntSet, key: int): PTrunk =
|
||||
proc intSetPut(t: var IntSet, key: int): PTrunk =
|
||||
var h = key and t.max
|
||||
while t.data[h] != nil:
|
||||
if t.data[h].key == key:
|
||||
while t.data[h] != nil:
|
||||
if t.data[h].key == key:
|
||||
return t.data[h]
|
||||
h = nextTry(h, t.max)
|
||||
if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
|
||||
@@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
|
||||
t.data[h] = result
|
||||
|
||||
proc contains*(s: IntSet, key: int): bool =
|
||||
## returns true iff `key` is in `s`.
|
||||
## returns true iff `key` is in `s`.
|
||||
var t = intSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
if t != nil:
|
||||
var u = key and TrunkMask
|
||||
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
|
||||
else:
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc incl*(s: var IntSet, key: int) =
|
||||
|
||||
proc incl*(s: var IntSet, key: int) =
|
||||
## includes an element `key` in `s`.
|
||||
var t = intSetPut(s, `shr`(key, TrunkShift))
|
||||
var u = key and TrunkMask
|
||||
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
|
||||
`shl`(1, u and IntMask)
|
||||
|
||||
proc excl*(s: var IntSet, key: int) =
|
||||
proc excl*(s: var IntSet, key: int) =
|
||||
## excludes `key` from the set `s`.
|
||||
var t = intSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
if t != nil:
|
||||
var u = key and TrunkMask
|
||||
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
|
||||
not `shl`(1, u and IntMask)
|
||||
|
||||
proc containsOrIncl*(s: var IntSet, key: int): bool =
|
||||
proc containsOrIncl*(s: var IntSet, key: int): bool =
|
||||
## returns true if `s` contains `key`, otherwise `key` is included in `s`
|
||||
## and false is returned.
|
||||
var t = intSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
if t != nil:
|
||||
var u = key and TrunkMask
|
||||
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
|
||||
if not result:
|
||||
if not result:
|
||||
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
|
||||
`shl`(1, u and IntMask)
|
||||
else:
|
||||
else:
|
||||
incl(s, key)
|
||||
result = false
|
||||
|
||||
|
||||
proc initIntSet*: IntSet =
|
||||
## creates a new int set that is empty.
|
||||
newSeq(result.data, InitIntSetSize)
|
||||
@@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
|
||||
|
||||
proc assign*(dest: var IntSet, src: IntSet) =
|
||||
## copies `src` to `dest`. `dest` does not need to be initialized by
|
||||
## `initIntSet`.
|
||||
## `initIntSet`.
|
||||
dest.counter = src.counter
|
||||
dest.max = src.max
|
||||
newSeq(dest.data, src.data.len)
|
||||
|
||||
|
||||
var it = src.head
|
||||
while it != nil:
|
||||
|
||||
|
||||
var h = it.key and dest.max
|
||||
while dest.data[h] != nil: h = nextTry(h, dest.max)
|
||||
assert(dest.data[h] == nil)
|
||||
@@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
|
||||
while r != nil:
|
||||
var i = 0
|
||||
while i <= high(r.bits):
|
||||
var w = r.bits[i]
|
||||
var w = r.bits[i]
|
||||
# taking a copy of r.bits[i] here is correct, because
|
||||
# modifying operations are not allowed during traversation
|
||||
var j = 0
|
||||
@@ -198,14 +198,21 @@ proc empty*(s: IntSet): bool {.inline, deprecated.} =
|
||||
result = s.counter == 0
|
||||
|
||||
when isMainModule:
|
||||
import sequtils, algorithm
|
||||
|
||||
var x = initIntSet()
|
||||
x.incl(1)
|
||||
x.incl(2)
|
||||
x.incl(7)
|
||||
x.incl(1056)
|
||||
for e in items(x): echo e
|
||||
|
||||
var y: TIntSet
|
||||
var xs = toSeq(items(x))
|
||||
xs.sort(cmp[int])
|
||||
assert xs == @[1, 2, 7, 1056]
|
||||
|
||||
var y: IntSet
|
||||
assign(y, x)
|
||||
for e in items(y): echo e
|
||||
var ys = toSeq(items(y))
|
||||
ys.sort(cmp[int])
|
||||
assert ys == @[1, 2, 7, 1056]
|
||||
|
||||
|
||||
@@ -492,9 +492,8 @@ when isMainModule:
|
||||
|
||||
block: # filter iterator test
|
||||
let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
||||
echo($n)
|
||||
# echoes 4, 8, 4 in separate lines
|
||||
assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
|
||||
@[4, 8, 4]
|
||||
|
||||
block: # keepIf test
|
||||
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
|
||||
@@ -616,4 +615,5 @@ when isMainModule:
|
||||
#doAssert a.repeat(-1) == @[] # will not compile!
|
||||
doAssert b.repeat(3) == @[]
|
||||
|
||||
echo "Finished doc tests"
|
||||
when not defined(testing):
|
||||
echo "Finished doc tests"
|
||||
|
||||
@@ -114,7 +114,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc rightSize*(count: int): int {.inline.} =
|
||||
proc rightSize*(count: Natural): int {.inline.} =
|
||||
## Return the value of `initialSize` to support `count` items.
|
||||
##
|
||||
## If more items are expected to be added, simply add that
|
||||
@@ -798,177 +798,179 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
|
||||
g = nxg
|
||||
result = compared == s.counter
|
||||
|
||||
proc testModule() =
|
||||
## Internal micro test to validate docstrings and such.
|
||||
block isValidTest:
|
||||
var options: HashSet[string]
|
||||
proc savePreferences(options: HashSet[string]) =
|
||||
assert options.isValid, "Pass an initialized set!"
|
||||
options = initSet[string]()
|
||||
options.savePreferences
|
||||
when isMainModule and not defined(release):
|
||||
proc testModule() =
|
||||
## Internal micro test to validate docstrings and such.
|
||||
block isValidTest:
|
||||
var options: HashSet[string]
|
||||
proc savePreferences(options: HashSet[string]) =
|
||||
assert options.isValid, "Pass an initialized set!"
|
||||
options = initSet[string]()
|
||||
options.savePreferences
|
||||
|
||||
block lenTest:
|
||||
var values: HashSet[int]
|
||||
assert(not values.isValid)
|
||||
assert values.len == 0
|
||||
assert values.card == 0
|
||||
block lenTest:
|
||||
var values: HashSet[int]
|
||||
assert(not values.isValid)
|
||||
assert values.len == 0
|
||||
assert values.card == 0
|
||||
|
||||
block setIterator:
|
||||
type pair = tuple[a, b: int]
|
||||
var a, b = initSet[pair]()
|
||||
a.incl((2, 3))
|
||||
a.incl((3, 2))
|
||||
a.incl((2, 3))
|
||||
for x, y in a.items:
|
||||
b.incl((x - 2, y + 1))
|
||||
assert a.len == b.card
|
||||
assert a.len == 2
|
||||
#echo b
|
||||
block setIterator:
|
||||
type pair = tuple[a, b: int]
|
||||
var a, b = initSet[pair]()
|
||||
a.incl((2, 3))
|
||||
a.incl((3, 2))
|
||||
a.incl((2, 3))
|
||||
for x, y in a.items:
|
||||
b.incl((x - 2, y + 1))
|
||||
assert a.len == b.card
|
||||
assert a.len == 2
|
||||
#echo b
|
||||
|
||||
block setContains:
|
||||
var values = initSet[int]()
|
||||
assert(not values.contains(2))
|
||||
values.incl(2)
|
||||
assert values.contains(2)
|
||||
values.excl(2)
|
||||
assert(not values.contains(2))
|
||||
block setContains:
|
||||
var values = initSet[int]()
|
||||
assert(not values.contains(2))
|
||||
values.incl(2)
|
||||
assert values.contains(2)
|
||||
values.excl(2)
|
||||
assert(not values.contains(2))
|
||||
|
||||
values.incl(4)
|
||||
var others = toSet([6, 7])
|
||||
values.incl(others)
|
||||
assert values.len == 3
|
||||
values.incl(4)
|
||||
var others = toSet([6, 7])
|
||||
values.incl(others)
|
||||
assert values.len == 3
|
||||
|
||||
values.init
|
||||
assert values.containsOrIncl(2) == false
|
||||
assert values.containsOrIncl(2) == true
|
||||
var
|
||||
a = toSet([1, 2])
|
||||
b = toSet([1])
|
||||
b.incl(2)
|
||||
assert a == b
|
||||
values.init
|
||||
assert values.containsOrIncl(2) == false
|
||||
assert values.containsOrIncl(2) == true
|
||||
var
|
||||
a = toSet([1, 2])
|
||||
b = toSet([1])
|
||||
b.incl(2)
|
||||
assert a == b
|
||||
|
||||
block exclusions:
|
||||
var s = toSet([2, 3, 6, 7])
|
||||
s.excl(2)
|
||||
s.excl(2)
|
||||
assert s.len == 3
|
||||
block exclusions:
|
||||
var s = toSet([2, 3, 6, 7])
|
||||
s.excl(2)
|
||||
s.excl(2)
|
||||
assert s.len == 3
|
||||
|
||||
var
|
||||
numbers = toSet([1, 2, 3, 4, 5])
|
||||
even = toSet([2, 4, 6, 8])
|
||||
numbers.excl(even)
|
||||
#echo numbers
|
||||
# --> {1, 3, 5}
|
||||
var
|
||||
numbers = toSet([1, 2, 3, 4, 5])
|
||||
even = toSet([2, 4, 6, 8])
|
||||
numbers.excl(even)
|
||||
#echo numbers
|
||||
# --> {1, 3, 5}
|
||||
|
||||
block toSeqAndString:
|
||||
var a = toSet([2, 4, 5])
|
||||
var b = initSet[int]()
|
||||
for x in [2, 4, 5]: b.incl(x)
|
||||
assert($a == $b)
|
||||
#echo a
|
||||
#echo toSet(["no", "esc'aping", "is \" provided"])
|
||||
block toSeqAndString:
|
||||
var a = toSet([2, 4, 5])
|
||||
var b = initSet[int]()
|
||||
for x in [2, 4, 5]: b.incl(x)
|
||||
assert($a == $b)
|
||||
#echo a
|
||||
#echo toSet(["no", "esc'aping", "is \" provided"])
|
||||
|
||||
#block orderedToSeqAndString:
|
||||
# echo toOrderedSet([2, 4, 5])
|
||||
# echo toOrderedSet(["no", "esc'aping", "is \" provided"])
|
||||
#block orderedToSeqAndString:
|
||||
# echo toOrderedSet([2, 4, 5])
|
||||
# echo toOrderedSet(["no", "esc'aping", "is \" provided"])
|
||||
|
||||
block setOperations:
|
||||
var
|
||||
a = toSet(["a", "b"])
|
||||
b = toSet(["b", "c"])
|
||||
c = union(a, b)
|
||||
assert c == toSet(["a", "b", "c"])
|
||||
var d = intersection(a, b)
|
||||
assert d == toSet(["b"])
|
||||
var e = difference(a, b)
|
||||
assert e == toSet(["a"])
|
||||
var f = symmetricDifference(a, b)
|
||||
assert f == toSet(["a", "c"])
|
||||
assert d < a and d < b
|
||||
assert((a < a) == false)
|
||||
assert d <= a and d <= b
|
||||
assert((a <= a))
|
||||
# Alias test.
|
||||
assert a + b == toSet(["a", "b", "c"])
|
||||
assert a * b == toSet(["b"])
|
||||
assert a - b == toSet(["a"])
|
||||
assert a -+- b == toSet(["a", "c"])
|
||||
assert disjoint(a, b) == false
|
||||
assert disjoint(a, b - a) == true
|
||||
block setOperations:
|
||||
var
|
||||
a = toSet(["a", "b"])
|
||||
b = toSet(["b", "c"])
|
||||
c = union(a, b)
|
||||
assert c == toSet(["a", "b", "c"])
|
||||
var d = intersection(a, b)
|
||||
assert d == toSet(["b"])
|
||||
var e = difference(a, b)
|
||||
assert e == toSet(["a"])
|
||||
var f = symmetricDifference(a, b)
|
||||
assert f == toSet(["a", "c"])
|
||||
assert d < a and d < b
|
||||
assert((a < a) == false)
|
||||
assert d <= a and d <= b
|
||||
assert((a <= a))
|
||||
# Alias test.
|
||||
assert a + b == toSet(["a", "b", "c"])
|
||||
assert a * b == toSet(["b"])
|
||||
assert a - b == toSet(["a"])
|
||||
assert a -+- b == toSet(["a", "c"])
|
||||
assert disjoint(a, b) == false
|
||||
assert disjoint(a, b - a) == true
|
||||
|
||||
block mapSet:
|
||||
var a = toSet([1, 2, 3])
|
||||
var b = a.map(proc (x: int): string = $x)
|
||||
assert b == toSet(["1", "2", "3"])
|
||||
block mapSet:
|
||||
var a = toSet([1, 2, 3])
|
||||
var b = a.map(proc (x: int): string = $x)
|
||||
assert b == toSet(["1", "2", "3"])
|
||||
|
||||
block isValidTest:
|
||||
var cards: OrderedSet[string]
|
||||
proc saveTarotCards(cards: OrderedSet[string]) =
|
||||
assert cards.isValid, "Pass an initialized set!"
|
||||
cards = initOrderedSet[string]()
|
||||
cards.saveTarotCards
|
||||
block isValidTest:
|
||||
var cards: OrderedSet[string]
|
||||
proc saveTarotCards(cards: OrderedSet[string]) =
|
||||
assert cards.isValid, "Pass an initialized set!"
|
||||
cards = initOrderedSet[string]()
|
||||
cards.saveTarotCards
|
||||
|
||||
block lenTest:
|
||||
var values: OrderedSet[int]
|
||||
assert(not values.isValid)
|
||||
assert values.len == 0
|
||||
assert values.card == 0
|
||||
block lenTest:
|
||||
var values: OrderedSet[int]
|
||||
assert(not values.isValid)
|
||||
assert values.len == 0
|
||||
assert values.card == 0
|
||||
|
||||
block setIterator:
|
||||
type pair = tuple[a, b: int]
|
||||
var a, b = initOrderedSet[pair]()
|
||||
a.incl((2, 3))
|
||||
a.incl((3, 2))
|
||||
a.incl((2, 3))
|
||||
for x, y in a.items:
|
||||
b.incl((x - 2, y + 1))
|
||||
assert a.len == b.card
|
||||
assert a.len == 2
|
||||
block setIterator:
|
||||
type pair = tuple[a, b: int]
|
||||
var a, b = initOrderedSet[pair]()
|
||||
a.incl((2, 3))
|
||||
a.incl((3, 2))
|
||||
a.incl((2, 3))
|
||||
for x, y in a.items:
|
||||
b.incl((x - 2, y + 1))
|
||||
assert a.len == b.card
|
||||
assert a.len == 2
|
||||
|
||||
#block orderedSetIterator:
|
||||
# var a = initOrderedSet[int]()
|
||||
# for value in [9, 2, 1, 5, 1, 8, 4, 2]:
|
||||
# a.incl(value)
|
||||
# for value in a.items:
|
||||
# echo "Got ", value
|
||||
#block orderedSetIterator:
|
||||
# var a = initOrderedSet[int]()
|
||||
# for value in [9, 2, 1, 5, 1, 8, 4, 2]:
|
||||
# a.incl(value)
|
||||
# for value in a.items:
|
||||
# echo "Got ", value
|
||||
|
||||
block setContains:
|
||||
var values = initOrderedSet[int]()
|
||||
assert(not values.contains(2))
|
||||
values.incl(2)
|
||||
assert values.contains(2)
|
||||
block setContains:
|
||||
var values = initOrderedSet[int]()
|
||||
assert(not values.contains(2))
|
||||
values.incl(2)
|
||||
assert values.contains(2)
|
||||
|
||||
block toSeqAndString:
|
||||
var a = toOrderedSet([2, 4, 5])
|
||||
var b = initOrderedSet[int]()
|
||||
for x in [2, 4, 5]: b.incl(x)
|
||||
assert($a == $b)
|
||||
assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
|
||||
block toSeqAndString:
|
||||
var a = toOrderedSet([2, 4, 5])
|
||||
var b = initOrderedSet[int]()
|
||||
for x in [2, 4, 5]: b.incl(x)
|
||||
assert($a == $b)
|
||||
assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
|
||||
|
||||
block initBlocks:
|
||||
var a: OrderedSet[int]
|
||||
a.init(4)
|
||||
a.incl(2)
|
||||
a.init
|
||||
assert a.len == 0 and a.isValid
|
||||
a = initOrderedSet[int](4)
|
||||
a.incl(2)
|
||||
assert a.len == 1
|
||||
block initBlocks:
|
||||
var a: OrderedSet[int]
|
||||
a.init(4)
|
||||
a.incl(2)
|
||||
a.init
|
||||
assert a.len == 0 and a.isValid
|
||||
a = initOrderedSet[int](4)
|
||||
a.incl(2)
|
||||
assert a.len == 1
|
||||
|
||||
var b: HashSet[int]
|
||||
b.init(4)
|
||||
b.incl(2)
|
||||
b.init
|
||||
assert b.len == 0 and b.isValid
|
||||
b = initSet[int](4)
|
||||
b.incl(2)
|
||||
assert b.len == 1
|
||||
var b: HashSet[int]
|
||||
b.init(4)
|
||||
b.incl(2)
|
||||
b.init
|
||||
assert b.len == 0 and b.isValid
|
||||
b = initSet[int](4)
|
||||
b.incl(2)
|
||||
assert b.len == 1
|
||||
|
||||
for i in 0 .. 32:
|
||||
var s = rightSize(i)
|
||||
if s <= i or mustRehash(s, i):
|
||||
echo "performance issue: rightSize() will not elide enlarge() at ", i
|
||||
for i in 0 .. 32:
|
||||
var s = rightSize(i)
|
||||
if s <= i or mustRehash(s, i):
|
||||
echo "performance issue: rightSize() will not elide enlarge() at ", i
|
||||
|
||||
echo "Micro tests run successfully."
|
||||
when not defined(testing):
|
||||
echo "Micro tests run successfully."
|
||||
|
||||
when isMainModule and not defined(release): testModule()
|
||||
testModule()
|
||||
|
||||
@@ -128,7 +128,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc rightSize*(count: int): int {.inline.} =
|
||||
proc rightSize*(count: Natural): int {.inline.} =
|
||||
## Return the value of `initialSize` to support `count` items.
|
||||
##
|
||||
## If more items are expected to be added, simply add that
|
||||
@@ -984,6 +984,22 @@ proc sort*[A](t: CountTableRef[A]) =
|
||||
## `t` in the sorted order.
|
||||
t[].sort
|
||||
|
||||
proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
|
||||
## merges the second table into the first one
|
||||
for key, value in t:
|
||||
s.inc(key, value)
|
||||
|
||||
proc merge*[A](s, t: CountTable[A]): CountTable[A] =
|
||||
## merges the two tables into a new one
|
||||
result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
|
||||
for table in @[s, t]:
|
||||
for key, value in table:
|
||||
result.inc(key, value)
|
||||
|
||||
proc merge*[A](s, t: CountTableRef[A]) =
|
||||
## merges the second table into the first one
|
||||
s[].merge(t[])
|
||||
|
||||
when isMainModule:
|
||||
type
|
||||
Person = object
|
||||
@@ -1012,3 +1028,48 @@ when isMainModule:
|
||||
s2[p2] = 45_000
|
||||
s3[p1] = 30_000
|
||||
s3[p2] = 45_000
|
||||
|
||||
var
|
||||
t1 = initCountTable[string]()
|
||||
t2 = initCountTable[string]()
|
||||
t1.inc("foo")
|
||||
t1.inc("bar", 2)
|
||||
t1.inc("baz", 3)
|
||||
t2.inc("foo", 4)
|
||||
t2.inc("bar")
|
||||
t2.inc("baz", 11)
|
||||
merge(t1, t2)
|
||||
assert(t1["foo"] == 5)
|
||||
assert(t1["bar"] == 3)
|
||||
assert(t1["baz"] == 14)
|
||||
|
||||
let
|
||||
t1r = newCountTable[string]()
|
||||
t2r = newCountTable[string]()
|
||||
t1r.inc("foo")
|
||||
t1r.inc("bar", 2)
|
||||
t1r.inc("baz", 3)
|
||||
t2r.inc("foo", 4)
|
||||
t2r.inc("bar")
|
||||
t2r.inc("baz", 11)
|
||||
merge(t1r, t2r)
|
||||
assert(t1r["foo"] == 5)
|
||||
assert(t1r["bar"] == 3)
|
||||
assert(t1r["baz"] == 14)
|
||||
|
||||
var
|
||||
t1l = initCountTable[string]()
|
||||
t2l = initCountTable[string]()
|
||||
t1l.inc("foo")
|
||||
t1l.inc("bar", 2)
|
||||
t1l.inc("baz", 3)
|
||||
t2l.inc("foo", 4)
|
||||
t2l.inc("bar")
|
||||
t2l.inc("baz", 11)
|
||||
let
|
||||
t1merging = t1l
|
||||
t2merging = t2l
|
||||
let merged = merge(t1merging, t2merging)
|
||||
assert(merged["foo"] == 5)
|
||||
assert(merged["bar"] == 3)
|
||||
assert(merged["baz"] == 14)
|
||||
|
||||
@@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
|
||||
result = doNothing
|
||||
inc s.calls
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc busyLoop() =
|
||||
while true:
|
||||
discard random(80)
|
||||
|
||||
@@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
|
||||
when isMainModule:
|
||||
var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
|
||||
|
||||
echo(setCookie("test", "value", tim.getGMTime()))
|
||||
let cookie = setCookie("test", "value", tim.getGMTime())
|
||||
when not defined(testing):
|
||||
echo cookie
|
||||
let start = "Set-Cookie: test=value; Expires="
|
||||
assert cookie[0..start.high] == start
|
||||
|
||||
echo parseCookies("uid=1; kp=2")
|
||||
let table = parseCookies("uid=1; kp=2")
|
||||
assert table["uid"] == "1"
|
||||
assert table["kp"] == "2"
|
||||
|
||||
@@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
|
||||
finally:
|
||||
close(c)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
let
|
||||
orig = "öäüß"
|
||||
cp1252 = convert(orig, "CP1252", "UTF-8")
|
||||
|
||||
@@ -198,7 +198,7 @@ proc register*(d: Dispatcher, monitor: FSMonitor,
|
||||
var deleg = toDelegate(monitor)
|
||||
d.register(deleg)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
var disp = newDispatcher()
|
||||
var monitor = newMonitor()
|
||||
|
||||
@@ -629,7 +629,7 @@ when isMainModule:
|
||||
if not d.poll(): break
|
||||
main()
|
||||
|
||||
when isMainModule and false:
|
||||
when not defined(testing) and isMainModule:
|
||||
var ftp = ftpClient("example.com", user = "foo", pass = "bar")
|
||||
ftp.connect()
|
||||
echo ftp.pwd()
|
||||
|
||||
@@ -186,8 +186,19 @@ when isMainModule:
|
||||
assert( z["first"]["one"] == 1) # retrieve from first inner table
|
||||
assert( z["second"]["red"] == 10) # retrieve from second inner table
|
||||
|
||||
for k,v in pairs(z):
|
||||
echo( "$# ($#) ->" % [k,$len(v)] )
|
||||
#for k2,v2 in pairs(v):
|
||||
# echo( " $# <-> $#" % [k2,$v2] )
|
||||
echo()
|
||||
var output = ""
|
||||
for k, v in pairs(z):
|
||||
output.add( "$# ($#) ->\n" % [k,$len(v)] )
|
||||
for k2,v2 in pairs(v):
|
||||
output.add( " $# <-> $#\n" % [k2,$v2] )
|
||||
|
||||
let expected = unindent """
|
||||
first (3) ->
|
||||
two <-> 2
|
||||
three <-> 3
|
||||
one <-> 1
|
||||
second (2) ->
|
||||
red <-> 10
|
||||
blue <-> 20
|
||||
"""
|
||||
assert output == expected
|
||||
|
||||
@@ -483,7 +483,8 @@ macro `var`*(e: expr): expr {.immediate.} =
|
||||
result = xmlCheckedTag(e, "var", commonAttr)
|
||||
|
||||
when isMainModule:
|
||||
var nim = "Nim"
|
||||
echo h1(a(href="http://nim-lang.org", nim))
|
||||
echo form(action="test", `accept-charset` = "Content-Type")
|
||||
|
||||
let nim = "Nim"
|
||||
assert h1(a(href="http://nim-lang.org", nim)) ==
|
||||
"""<h1><a href="http://nim-lang.org">Nim</a></h1>"""
|
||||
assert form(action="test", `accept-charset` = "Content-Type") ==
|
||||
"""<form action="test" accept-charset="Content-Type"></form>"""
|
||||
|
||||
@@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
|
||||
var errors: seq[string] = @[]
|
||||
result = loadHtml(path, errors)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import os
|
||||
|
||||
var errors: seq[string] = @[]
|
||||
|
||||
@@ -819,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
|
||||
result = await client.request(redirectTo, httpGET)
|
||||
lastUrl = redirectTo
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
when true:
|
||||
# Async
|
||||
proc main() {.async.} =
|
||||
|
||||
@@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
|
||||
## Closes the ``PAsyncHTTPServer``.
|
||||
h.asyncSocket.close()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var counter = 0
|
||||
|
||||
var s: TServer
|
||||
|
||||
@@ -605,6 +605,49 @@ proc newJArray*(): JsonNode =
|
||||
result.kind = JArray
|
||||
result.elems = @[]
|
||||
|
||||
proc getStr*(n: JsonNode, default: string = ""): string =
|
||||
## Retrieves the string value of a `JString JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JString``.
|
||||
if n.kind != JString: return default
|
||||
else: return n.str
|
||||
|
||||
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
|
||||
## Retrieves the int value of a `JInt JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JInt``.
|
||||
if n.kind != JInt: return default
|
||||
else: return n.num
|
||||
|
||||
proc getFNum*(n: JsonNode, default: float = 0.0): float =
|
||||
## Retrieves the float value of a `JFloat JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JFloat``.
|
||||
if n.kind != JFloat: return default
|
||||
else: return n.fnum
|
||||
|
||||
proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||
## Retrieves the bool value of a `JBool JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JBool``.
|
||||
if n.kind != JBool: return default
|
||||
else: return n.bval
|
||||
|
||||
proc getFields*(n: JsonNode,
|
||||
default: seq[tuple[key: string, val: JsonNode]] = @[]):
|
||||
seq[tuple[key: string, val: JsonNode]] =
|
||||
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JObject``.
|
||||
if n.kind != JObject: return default
|
||||
else: return n.fields
|
||||
|
||||
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
|
||||
## Retrieves the int value of a `JArray JsonNode`.
|
||||
##
|
||||
## Returns ``default`` if ``n`` is not a ``JArray``.
|
||||
if n.kind != JArray: return default
|
||||
else: return n.elems
|
||||
|
||||
proc `%`*(s: string): JsonNode =
|
||||
## Generic constructor for JSON data. Creates a new `JString JsonNode`.
|
||||
@@ -765,22 +808,25 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
|
||||
return
|
||||
obj.fields.add((key, val))
|
||||
|
||||
proc `{}`*(node: JsonNode, key: string): JsonNode =
|
||||
## Transverses the node and gets the given value. If any of the
|
||||
## names does not exist, returns nil
|
||||
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
||||
## Traverses the node and gets the given value. If any of the
|
||||
## keys do not exist, returns nil. Also returns nil if one of the
|
||||
## intermediate data structures is not an object
|
||||
result = node
|
||||
if isNil(node): return nil
|
||||
result = result[key]
|
||||
for key in keys:
|
||||
if isNil(result) or result.kind!=JObject:
|
||||
return nil
|
||||
result=result[key]
|
||||
|
||||
proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
|
||||
## Transverses the node and tries to set the value at the given location
|
||||
## to `value` If any of the names are missing, they are added
|
||||
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
||||
## Traverses the node and tries to set the value at the given location
|
||||
## to `value` If any of the keys are missing, they are added
|
||||
var node = node
|
||||
for i in 0..(names.len-2):
|
||||
if isNil(node[names[i]]):
|
||||
node[names[i]] = newJObject()
|
||||
node = node[names[i]]
|
||||
node[names[names.len-1]] = value
|
||||
for i in 0..(keys.len-2):
|
||||
if isNil(node[keys[i]]):
|
||||
node[keys[i]] = newJObject()
|
||||
node = node[keys[i]]
|
||||
node[keys[keys.len-1]] = value
|
||||
|
||||
proc delete*(obj: JsonNode, key: string) =
|
||||
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
|
||||
@@ -1107,19 +1153,22 @@ when false:
|
||||
when isMainModule:
|
||||
#var node = parse("{ \"test\": null }")
|
||||
#echo(node.existsKey("test56"))
|
||||
|
||||
var parsed = parseFile("tests/testdata/jsontest.json")
|
||||
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
||||
echo(parsed)
|
||||
echo()
|
||||
echo(pretty(parsed, 2))
|
||||
echo()
|
||||
echo(parsed["keyÄÖöoßß"])
|
||||
echo()
|
||||
echo(pretty(parsed2))
|
||||
try:
|
||||
echo(parsed["key2"][12123])
|
||||
raise newException(ValueError, "That line was expected to fail")
|
||||
except IndexError: echo()
|
||||
|
||||
when not defined(testing):
|
||||
echo(parsed)
|
||||
echo()
|
||||
echo(pretty(parsed, 2))
|
||||
echo()
|
||||
echo(parsed["keyÄÖöoßß"])
|
||||
echo()
|
||||
echo(pretty(parsed2))
|
||||
try:
|
||||
echo(parsed["key2"][12123])
|
||||
raise newException(ValueError, "That line was expected to fail")
|
||||
except IndexError: echo()
|
||||
|
||||
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
|
||||
# nil passthrough
|
||||
@@ -1143,9 +1192,17 @@ when isMainModule:
|
||||
except:
|
||||
assert(false, "EInvalidIndex thrown for valid index")
|
||||
|
||||
assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
|
||||
assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
|
||||
assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
||||
assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
|
||||
|
||||
# Generator:
|
||||
var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
|
||||
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
var j2 = %*
|
||||
[
|
||||
@@ -1173,12 +1230,13 @@ when isMainModule:
|
||||
}
|
||||
]
|
||||
assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
discard """
|
||||
while true:
|
||||
var json = stdin.readLine()
|
||||
var node = parse(json)
|
||||
echo(node)
|
||||
echo()
|
||||
echo()
|
||||
"""
|
||||
|
||||
when not defined(testing):
|
||||
discard """
|
||||
while true:
|
||||
var json = stdin.readLine()
|
||||
var node = parse(json)
|
||||
echo(node)
|
||||
echo()
|
||||
echo()
|
||||
"""
|
||||
|
||||
@@ -278,7 +278,7 @@ proc getLogFilter*(): Level =
|
||||
|
||||
# --------------
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var L = newConsoleLogger()
|
||||
var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
|
||||
var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
|
||||
|
||||
@@ -244,7 +244,7 @@ proc to*[T](data: string): T =
|
||||
var tab = initTable[BiggestInt, pointer]()
|
||||
loadAny(newStringStream(data), toAny(result), tab)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
template testit(x: expr) = echo($$to[type(x)]($$x))
|
||||
|
||||
var x: array[0..4, array[0..4, string]] = [
|
||||
|
||||
@@ -152,6 +152,7 @@ proc randomize*(seed: int) {.benign.}
|
||||
## Note: Does nothing for the JavaScript target,
|
||||
## as JavaScript does not support this.
|
||||
|
||||
{.push noSideEffect.}
|
||||
when not defined(JS):
|
||||
proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
|
||||
## computes the square root of `x`.
|
||||
@@ -273,6 +274,8 @@ else:
|
||||
var y = exp(2.0*x)
|
||||
return (y-1.0)/(y+1.0)
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc `mod`*(x, y: float): float =
|
||||
result = if y == 0.0: x else: x - y * (x/y).floor
|
||||
|
||||
@@ -369,4 +372,10 @@ when isMainModule and not defined(JS):
|
||||
randomize(seed)
|
||||
for i in 0..SIZE-1:
|
||||
assert buf[i] == random(high(int)), "non deterministic random seeding"
|
||||
echo "random values equal after reseeding"
|
||||
|
||||
when not defined(testing):
|
||||
echo "random values equal after reseeding"
|
||||
|
||||
# Check for no side effect annotation
|
||||
proc mySqrt(num: float): float {.noSideEffect.} =
|
||||
return sqrt(num)
|
||||
|
||||
@@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
|
||||
return int(y)
|
||||
|
||||
# Test
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var mt = newMersenneTwister(2525)
|
||||
|
||||
for i in 0..99:
|
||||
|
||||
@@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
|
||||
|
||||
when isMainModule:
|
||||
var m = newMimetypes()
|
||||
echo m.getMimetype("mp4")
|
||||
echo m.getExt("text/html")
|
||||
assert m.getMimetype("mp4") == "video/mp4"
|
||||
assert m.getExt("text/html") == "html"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user