Merge remote-tracking branch 'origin/devel' into initallocator-fix

This commit is contained in:
Jacek Sieka
2016-08-25 22:59:51 +08:00
434 changed files with 22365 additions and 6316 deletions

5
.gitignore vendored
View File

@@ -10,6 +10,7 @@ nimcache/
*.dylib
*.zip
*.iss
*.log
mapping.txt
tags
@@ -42,3 +43,7 @@ xcuserdata/
/testresults.json
testament.db
/csources
# Private directories and files (IDEs)
.*/
~*

View File

@@ -10,7 +10,7 @@ addons:
- libgc-dev
before_script:
- set -e
- wget http://flatassembler.net/fasm-1.71.39.tgz
- wget http://nim-lang.org/download/fasm-1.71.39.tgz
- tar xvf fasm-1.71.39.tgz
- git clone --depth 1 https://github.com/nim-lang/csources.git
- cd csources
@@ -23,6 +23,7 @@ script:
- ./koch boot
- ./koch boot -d:release
- nim e install_nimble.nims
- nim e tests/test_nimscript.nims
- nimble update
- nimble install zip
- nimble install opengl

View File

@@ -18,5 +18,3 @@ set +x
echo
echo 'Install Nim using "./install.sh <dir>" or "sudo ./install.sh <dir>".'
exit 0

View File

@@ -1,6 +1,6 @@
[Package]
name = "compiler"
version = "0.13.0"
version = "0.14.3"
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
@@ -8,4 +8,4 @@ license = "MIT"
InstallDirs = "doc, compiler"
[Deps]
Requires: "nim >= 0.12.0"
Requires: "nim >= 0.13.0"

View File

@@ -271,13 +271,14 @@ type
TSymFlags* = set[TSymFlag]
const
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
sfNoInit* = sfMainModule # don't generate code to init the variable
sfImmediate* = sfDeadCodeElim
# macro or template is immediately expanded
# without considering any possible overloads
sfAllUntyped* = sfVolatile # macro or template is immediately expanded \
# in a generic context
sfDirty* = sfPure
# template is not hygienic (old styled template)
@@ -395,6 +396,9 @@ type
# sons[1]: field type
# .n: nkDotExpr storing the field name
tyVoid #\
# now different from tyEmpty, hurray!
static:
# remind us when TTypeKind stops to fit in a single 64-bit word
assert TTypeKind.high.ord <= 63
@@ -528,8 +532,6 @@ const
tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
# 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
# deprecated and this mess can be cleaned up.
tfVoid* = tfVarargs # for historical reasons we conflated 'void' with
# 'empty' ('@[]' has the type 'seq[empty]').
tfReturnsNew* = tfInheritable
skError* = skUnknown
@@ -544,7 +546,7 @@ type
mEcho, mShallowCopy, mSlurp, mStaticExec,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd,
mNew, mNewFinalize, mNewSeq,
mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
mXLenStr, mXLenSeq,
mIncl, mExcl, mCard, mChr,
@@ -563,8 +565,8 @@ type
mEqEnum, mLeEnum, mLtEnum,
mEqCh, mLeCh, mLtCh,
mEqB, mLeB, mLtB,
mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mEqCString,
mXor, mEqProc,
mEqRef, mEqUntracedRef, mLePtr, mLtPtr,
mXor, mEqCString, mEqProc,
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
@@ -590,6 +592,7 @@ type
mNewString, mNewStringOfCap, mParseBiggestFloat,
mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal,
mInt, mInt8, mInt16, mInt32, mInt64,
mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
@@ -609,7 +612,7 @@ type
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mNGenSym,
mNimvm
mNimvm, mIntDefine, mStrDefine
# things that we can evaluate safely at compile time, even if not asked for it:
const
@@ -769,7 +772,7 @@ type
procInstCache*: seq[PInstantiation]
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
#scope*: PScope # the scope where the proc was defined
of skModule:
of skModule, skPackage:
# modules keep track of the generic symbols they use from other modules.
# this is because in incremental compilation, when a module is about to
# be replaced with a newer version, we must decrement the usage count
@@ -848,6 +851,7 @@ type
# see instantiateDestructor in semdestruct.nim
deepCopy*: PSym # overriden 'deepCopy' operation
assignment*: PSym # overriden '=' operator
methods*: seq[(int,PSym)] # attached methods
size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown
align*: int16 # the type's alignment requirements
@@ -938,7 +942,7 @@ const
genericParamsPos* = 2
paramsPos* = 3
pragmasPos* = 4
optimizedCodePos* = 5 # will be used for exception tracking
miscPos* = 5 # used for undocumented and hacky stuff
bodyPos* = 6 # position of body; use rodread.getBody() instead!
resultPos* = 7
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
@@ -961,6 +965,8 @@ const
skMethod, skConverter}
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
var
gMainPackageId*: int
proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds
@@ -984,12 +990,12 @@ proc add*(father, son: PNode) =
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
result = n.sons[i]
template `-|`*(b, s: expr): expr =
template `-|`*(b, s: untyped): untyped =
(if b >= 0: b else: s.len + b)
# son access operators with support for negative indices
template `{}`*(n: PNode, i: int): expr = n[i -| n]
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
template `{}=`*(n: PNode, i: int, s: PNode) =
n.sons[i -| n] = s
when defined(useNodeIds):
@@ -1584,7 +1590,7 @@ proc isAtom*(n: PNode): bool {.inline.} =
proc isEmptyType*(t: PType): bool {.inline.} =
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
result = t == nil or t.kind in {tyEmpty, tyStmt}
result = t == nil or t.kind in {tyVoid, tyStmt}
proc makeStmtList*(n: PNode): PNode =
if n.kind == nkStmtList:

View File

@@ -124,7 +124,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
of tyArray, tyArrayConstr:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
else:
else:
internalError("openArrayLoc: " & typeToString(a.t))
else: internalError("openArrayLoc: " & typeToString(a.t))
@@ -260,7 +260,11 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
else:
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
else:
result = genArgNoParam(p, ri.sons[i])
if tfVarargs notin typ.flags:
localError(ri.info, "wrong argument count")
result = nil
else:
result = genArgNoParam(p, ri.sons[i])
discard """
Dot call syntax in C++

View File

@@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope =
proc getStrLit(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq")
result = "TMP" & rope(backendId())
result = getTempName(m)
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), rope(len(s))])
@@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of nkNilLit:
let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = "TMP" & rope(id)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
if id == p.module.labels:
# not found in cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result])
@@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
elif skipTypes(ty, abstractVarRange).kind == tyString:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
if id == p.module.labels:
# string literal not found in the cache:
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, n.strVal)])
else:
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
[p.module.tmpBase, rope(id)])
else:
result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit:
@@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope =
var size = int(getSize(n.typ))
toBitSet(n, cs)
if size > 8:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = "TMP" & rope(id)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
if id == p.module.labels:
# not found in cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else:
@@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
var size = getSize(t)
let storage = if size < platform.intSize: rope("NI")
else: getTypeDesc(p.module, t)
result = getTempName()
result = getTempName(p.module)
linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum}:
@@ -591,7 +592,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"($1 == $2)", # EqPtr
"($1 <= $2)", # LePtr
"($1 < $2)", # LtPtr
"($1 == $2)", # EqCString
"($1 != $2)"] # Xor
var
a, b: TLoc
@@ -612,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if a.t.callConv == ccClosure:
if a.t.skipTypes(abstractInst).callConv == ccClosure:
putIntoDest(p, d, e.typ,
"($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
else:
@@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
#if e[0].kind != nkBracketExpr:
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
expr(p, e.sons[0], d)
if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
d.s = OnHeap
else:
var a: TLoc
let typ = skipTypes(e.sons[0].typ, abstractInst)
@@ -802,9 +804,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
v.r.add(d.loc.r)
genInExprAux(p, it, u, v, test)
let id = nodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
else: "TMP" & rope(id)
newStrNode(nkStrLit, field.name.s), p.module.labels)
let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
else: p.module.tmpBase & rope(id)
if op.magic == mNot:
linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@@ -1141,7 +1143,35 @@ proc genNewSeq(p: BProc, e: PNode) =
genNewSeqAux(p, a, b.rdLoc)
gcUsage(e)
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
let seqtype = skipTypes(e.typ, abstractVarRange)
var a: TLoc
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), a.rdLoc]))
gcUsage(e)
proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
if id == p.module.labels:
# expression not found in the cache:
inc(p.module.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true
else:
result = false
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
if handleConstExpr(p, e, d): return
#echo rendertree e, " ", e.isDeepConstExpr
var tmp: TLoc
var t = e.typ.skipTypes(abstractInst)
getTemp(p, t, tmp)
@@ -1235,7 +1265,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first:
let ti = genTypeInfo(p.module, dest)
if tfFinal in dest.flags or (p.module.objHasKidsValid and
if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
tfObjHasKids notin dest.flags):
result = "$1.m_type == $2" % [a, ti]
else:
@@ -1293,7 +1323,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.s)
of tyEnum, tyOrdinal:
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprEnum($1, $2)", [
ropecg(p.module, "#reprEnum((NI)$1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyString:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s)
@@ -1320,7 +1350,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyEmpty:
of tyEmpty, tyVoid:
localError(e.info, "'repr' doesn't support 'void' type")
else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
@@ -1558,11 +1588,12 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
proc genCast(p: BProc, e: PNode, d: var TLoc) =
const floatTypes = {tyFloat..tyFloat128}
const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject,
tyArray, tyArrayConstr}
let
destt = skipTypes(e.typ, abstractRange)
srct = skipTypes(e.sons[1].typ, abstractRange)
if destt.kind in floatTypes or srct.kind in floatTypes:
if destt.kind in ValueTypes or srct.kind in ValueTypes:
# 'cast' and some float type involved? --> use a union.
inc(p.labels)
var lbl = p.labels.rope
@@ -1668,10 +1699,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
else: unaryExpr(p, e, d, "#subInt($1, 1)")
of mInc, mDec:
const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
"$# = #subInt64($#, $#);$n"]
const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
"$# = #subInt($#, $#);$n"]
let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
@@ -1712,6 +1743,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNew: genNew(p, e)
of mNewFinalize: genNewFinalize(p, e)
of mNewSeq: genNewSeq(p, e)
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
@@ -1754,25 +1786,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, x, a)
initLocExpr(p, e.sons[2], b)
genDeepCopy(p, a, b)
of mDotDot: genCall(p, e, d)
of mDotDot, mEqCString: genCall(p, e, d)
else: internalError(e.info, "genMagicExpr: " & $op)
proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
fillLoc(d, locData, t, "TMP" & rope(id), OnStatic)
if id == gBackendId:
# expression not found in the cache:
inc(gBackendId)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true
else:
result = false
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
# example: { a..b, c, d, e, f..g }
# we have to emit an expression of the form:
@@ -1856,10 +1872,16 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[1], b)
if n.sons[0].skipConv.kind == nkClosure:
internalError(n.info, "closure to closure created")
getTemp(p, n.typ, tmp)
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
tmp.rdLoc, a.rdLoc, b.rdLoc)
putLocIntoDest(p, d, tmp)
# tasyncawait.nim breaks with this optimization:
when false:
if d.k != locNone:
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
d.rdLoc, a.rdLoc, b.rdLoc)
else:
getTemp(p, n.typ, tmp)
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
tmp.rdLoc, a.rdLoc, b.rdLoc)
putLocIntoDest(p, d, tmp)
proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
var arr: TLoc
@@ -1947,12 +1969,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var tmp = "TMP" & rope(id)
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
let tmp = p.module.tmpBase & rope(id)
if id == gBackendId:
if id == p.module.labels:
# expression not found in the cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
@@ -1960,6 +1982,10 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
fillLoc(d, locData, t, tmp, OnStatic)
else:
putDataIntoDest(p, d, t, tmp)
# This fixes bug #4551, but we really need better dataflow
# analysis to make this 100% safe.
if t.kind notin {tySequence, tyString}:
d.s = OnStatic
proc expr(p: BProc, n: PNode, d: var TLoc) =
case n.kind
@@ -1985,10 +2011,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skConst:
if sfFakeConst in sym.flags:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
putLocIntoDest(p, d, sym.loc)
elif isSimpleConst(sym.typ):
if isSimpleConst(sym.typ):
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic)
else:
genComplexConst(p, sym, d)
@@ -2160,7 +2183,8 @@ proc genConstSimpleList(p: BProc, n: PNode): Rope =
result = rope("{")
for i in countup(ord(n.kind == nkObjConstr), length - 2):
addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
if length > ord(n.kind == nkObjConstr):
add(result, genNamedConstExpr(p, n.sons[length - 1]))
addf(result, "}$n", [])
proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
@@ -2174,8 +2198,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
data.add("}")
data.add("}")
inc(gBackendId)
result = "CNSTSEQ" & gBackendId.rope
result = getTempName(p.module)
appcg(p.module, cfsData,
"NIM_CONST struct {$n" &

View File

@@ -107,13 +107,13 @@ proc genMergeInfo*(m: BModule): Rope =
writeIntSet(m.typeInfoMarker, s)
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" hasframe:")
encodeVInt(ord(m.frameDeclared), s)
s.add(" flags:")
encodeVInt(cast[int](m.flags), s)
s.add(tnl)
s.add("*/")
result = s.rope
template `^`(pos: int): expr = L.buf[pos]
template `^`(pos: int): untyped = L.buf[pos]
proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
@@ -222,13 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo": readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
of "flags":
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
else: internalError("ccgmerge: unknown key: " & k)
when not defined(nimhygiene):
{.pragma: inject.}
template withCFile(cfilename: string, body: stmt) {.immediate.} =
template withCFile(cfilename: string, body: untyped) =
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer

View File

@@ -16,7 +16,7 @@ const
# above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) =
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2} and
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
@@ -136,7 +136,7 @@ proc exprBlock(p: BProc, n: PNode, d: var TLoc) =
expr(p, n, d)
endBlock(p)
template preserveBreakIdx(body: stmt): stmt {.immediate.} =
template preserveBreakIdx(body: untyped): untyped =
var oldBreakIdx = p.breakIdx
body
p.breakIdx = oldBreakIdx
@@ -269,8 +269,6 @@ proc genConstStmt(p: BProc, t: PNode) =
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
var c = it.sons[0].sym
if c.typ.containsCompileTimeOnly: continue
if sfFakeConst in c.flags:
genSingleVar(p, it)
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
c.ast.len != 0:
if not emitLazily(c): requestConstImpl(p, c)
@@ -570,7 +568,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
genLineDir(p, t)
# reraise the last exception:
if p.module.compileToCpp:
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
line(p, cpsStmts, ~"throw;$n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n")
@@ -793,7 +791,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
genLineDir(p, t)
let exc = getTempName()
let exc = getTempName(p.module)
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
@@ -886,7 +884,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
getTemp(p, t.typ, d)
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName()
var safePoint = getTempName(p.module)
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
@@ -961,6 +959,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
var a: TLoc
initLocExpr(p, t.sons[i], a)
res.add($rdLoc(a))
elif sym.kind == skType:
res.add($getTypeDesc(p.module, sym.typ))
else:
var r = sym.loc.r
if r == nil:

View File

@@ -18,7 +18,7 @@ proc emulatedThreadVars(): bool =
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
p.module.usesThreadVars = true
incl p.module.flags, usesThreadVars
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
@@ -51,7 +51,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
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):
if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
for t in items(nimtvDeps): discard getTypeDesc(m, t)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])

View File

@@ -100,7 +100,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = getGlobalTempName()
result = getTempName(m)
case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
@@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = s.loc.r
result = getGlobalTempName()
result = getTempName(m)
if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)
@@ -143,7 +143,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p
let header = "N_NIMCALL(void, $1)()" % [result]
let header = "N_NIMCALL(void, $1)(void)" % [result]
genTraverseProc(c, sLoc, s.loc.t)
let generatedProc = "$1 {$n$2$3$4}$n" %

View File

@@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2016 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -11,6 +11,8 @@
# ------------------------- Name Mangling --------------------------------
import debuginfo
proc isKeyword(w: PIdent): bool =
# Nim and C++ share some keywords
# it's more efficient to test the whole Nim keywords range
@@ -23,70 +25,70 @@ proc isKeyword(w: PIdent): bool =
proc mangleField(name: PIdent): string =
result = mangle(name.s)
if isKeyword(name):
result[0] = result[0].toUpper # Mangling makes everything lowercase,
# but some identifiers are C keywords
result[0] = result[0].toUpperAscii
# Mangling makes everything lowercase,
# but some identifiers are C keywords
proc hashOwner(s: PSym): FilenameHash =
var m = s
while m.kind != skModule: m = m.owner
let p = m.owner
assert p.kind == skPackage
result = gDebugInfo.register(p.name.s, m.name.s)
proc mangleName(s: PSym): Rope =
result = s.loc.r
if result == nil:
when oKeepVariableNames:
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
not isKeyword(s.name)
# XXX: This is still very experimental
#
# Even with all these inefficient checks, the bootstrap
# time is actually improved. This is probably because so many
# rope concatenations are now eliminated.
#
# Future notes:
# sfFromGeneric seems to be needed in order to avoid multiple
# definitions of certain variables generated in transf with
# names such as:
# `r`, `res`
# I need to study where these come from.
#
# about sfShadowed:
# consider the following Nim code:
# var x = 10
# block:
# var x = something(x)
# The generated C code will be:
# NI x;
# x = 10;
# {
# NI x;
# x = something(x); // Oops, x is already shadowed here
# }
# Right now, we work-around by not keeping the original name
# of the shadowed variable, but we can do better - we can
# create an alternative reference to it in the outer scope and
# use that in the inner scope.
#
# about isCKeyword:
# Nim variable names can be C keywords.
# We need to avoid such names in the generated code.
# XXX: Study whether mangleName is called just once per variable.
# Otherwise, there might be better place to do this.
#
# about sfGlobal:
# This seems to be harder - a top level extern variable from
# another modules can have the same name as a local one.
# Maybe we should just implement sfShadowed for them too.
#
# about skForVar:
# These are not properly scoped now - we need to add blocks
# around for loops in transf
if keepOrigName:
result = s.name.s.mangle.rope
else:
add(result, rope(mangle(s.name.s)))
add(result, ~"_")
add(result, rope(s.id))
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
not isKeyword(s.name)
# Even with all these inefficient checks, the bootstrap
# time is actually improved. This is probably because so many
# rope concatenations are now eliminated.
#
# sfFromGeneric is needed in order to avoid multiple
# definitions of certain variables generated in transf with
# names such as:
# `r`, `res`
# I need to study where these come from.
#
# about sfShadowed:
# consider the following Nim code:
# var x = 10
# block:
# var x = something(x)
# The generated C code will be:
# NI x;
# x = 10;
# {
# NI x;
# x = something(x); // Oops, x is already shadowed here
# }
# Right now, we work-around by not keeping the original name
# of the shadowed variable, but we can do better - we can
# create an alternative reference to it in the outer scope and
# use that in the inner scope.
#
# about isCKeyword:
# Nim variable names can be C keywords.
# We need to avoid such names in the generated code.
#
# about sfGlobal:
# This seems to be harder - a top level extern variable from
# another modules can have the same name as a local one.
# Maybe we should just implement sfShadowed for them too.
#
# about skForVar:
# These are not properly scoped now - we need to add blocks
# around for loops in transf
result = s.name.s.mangle.rope
if keepOrigName:
result.add "0"
else:
add(result, rope(mangle(s.name.s)))
add(result, ~"_")
add(result, rope(s.id))
add(result, ~"_")
add(result, rope(hashOwner(s).BiggestInt))
s.loc.r = result
proc typeName(typ: PType): Rope =
@@ -137,6 +139,10 @@ proc mapType(typ: PType): TCTypeKind =
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
#of tySet:
# if mapSetType(base) == ctArray: result = ctPtrToArray
# else: result = ctPtr
# XXX for some reason this breaks the pegs module
else: result = ctPtr
of tyPointer: result = ctPtr
of tySequence: result = ctNimSeq
@@ -145,11 +151,15 @@ proc mapType(typ: PType): TCTypeKind =
of tyCString: result = ctCString
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(lastSon typ)
else: internalError("mapType")
else: internalError("mapType")
proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
else: result = mapType(typ)
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
#else:
result = mapType(typ)
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
@@ -196,11 +206,9 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope =
# linear search is not necessary anymore:
result = Rope(idTableGet(tab, key))
proc getTempName(): Rope =
result = rfmt(nil, "TMP$1", rope(backendId()))
proc getGlobalTempName(): Rope =
result = rfmt(nil, "TMP$1", rope(backendId()))
proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels)
inc m.labels
proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, typedescInst)
@@ -223,7 +231,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
proc fillResult(param: PSym) =
fillLoc(param.loc, locParam, param.typ, ~"Result",
OnStack)
if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
if mapReturnType(param.typ) != ctArray and isInvalidReturnType(param.typ):
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
@@ -238,22 +246,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
"NI", "NI8", "NI16", "NI32", "NI64",
"NF", "NF32", "NF64", "NF128",
"NU", "NU8", "NU16", "NU32", "NU64",]
"NU", "NU8", "NU16", "NU32", "NU64"]
case typ.kind
of tyPointer:
result = typeNameOrLiteral(typ, "void*")
of tyEnum:
if firstOrd(typ) < 0:
result = typeNameOrLiteral(typ, "NI32")
else:
case int(getSize(typ))
of 1: result = typeNameOrLiteral(typ, "NU8")
of 2: result = typeNameOrLiteral(typ, "NU16")
of 4: result = typeNameOrLiteral(typ, "NI32")
of 8: result = typeNameOrLiteral(typ, "NI64")
else:
internalError(typ.sym.info, "getSimpleTypeDesc: " & $(getSize(typ)))
result = nil
of tyString:
discard cgsym(m, "NimStringDesc")
result = typeNameOrLiteral(typ, "NimStringDesc*")
@@ -264,6 +260,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else: internalError("tyStatic for getSimpleTypeDesc")
of tyGenericInst:
result = getSimpleTypeDesc(m, lastSon typ)
else: result = nil
proc pushType(m: BModule, typ: PType) =
@@ -317,7 +318,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
result = getTypeDescAux(m, t, check)
proc paramStorageLoc(param: PSym): TStorageLoc =
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray, tyVarargs, tyArrayConstr}:
result = OnStack
else:
result = OnUnknown
@@ -326,7 +327,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true;
weakDep=false) =
params = nil
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
if t.sons[0] == nil or isInvalidReturnType(t.sons[0]):
rettype = ~"void"
else:
rettype = getTypeDescAux(m, t.sons[0], check)
@@ -359,10 +360,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
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]):
if t.sons[0] != nil and isInvalidReturnType(t.sons[0]):
var arr = t.sons[0]
if params != nil: add(params, ", ")
if (mapReturnType(t.sons[0]) != ctArray):
if mapReturnType(t.sons[0]) != ctArray:
add(params, getTypeDescWeak(m, arr, check))
add(params, "*")
else:
@@ -424,7 +425,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
addf(result, "union{$n$1} $2;$n", [unionBody, uname])
of nkSym:
field = n.sym
if field.typ.kind == tyEmpty: return
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
sname = mangleRecFieldName(field, rectype)
if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
@@ -483,7 +484,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
else:
addf(result, " {$n", [name])
var desc = getRecordFields(m, typ, check)
let desc = getRecordFields(m, typ, check)
if desc == nil and not hasField:
addf(result, "char dummy;$n", [])
else:
@@ -536,8 +537,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
result = getTypePre(m, t)
if result != nil: return
if containsOrIncl(check, t.id):
if isImportedCppType(typ) or isImportedCppType(t): return
internalError("cannot generate C type for: " & typeToString(typ))
if not (isImportedCppType(typ) or isImportedCppType(t)):
internalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow.
@@ -576,8 +577,37 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
result = getTypeDescAux(m, et, check) & star
idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs:
result = getTypeDescAux(m, t.sons[0], check) & "*"
result = getTypeDescWeak(m, t.sons[0], check) & "*"
idTablePut(m.typeCache, t, result)
of tyRange, tyEnum:
let t = if t.kind == tyRange: t.lastSon else: t
result = cacheGetType(m.typeCache, t)
if result == nil:
result = getTypeName(t)
if not (isImportedCppType(t) or
(sfImportc in t.sym.flags and t.sym.magic == mNone)):
idTablePut(m.typeCache, t, result)
var size: int
if firstOrd(t) < 0:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
size = 4
else:
size = int(getSize(t))
case size
of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result])
of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
else: internalError(t.sym.info, "getTypeDescAux: enum")
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
var vals: seq[(string, int)] = @[]
for i in countup(0, t.n.len - 1):
assert(t.n.sons[i].kind == nkSym)
let field = t.n.sons[i].sym
vals.add((field.name.s, field.position.int))
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
name: t.sym.name.s, values: vals))
of tyProc:
result = getTypeName(t)
idTablePut(m.typeCache, t, result)
@@ -642,7 +672,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
chunkStart = i
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
if typeInSlot == nil or typeInSlot.kind == tyEmpty:
if typeInSlot == nil or typeInSlot.kind == tyVoid:
result.add(~"void")
else:
result.add getTypeDescAux(m, typeInSlot, check)
@@ -654,7 +684,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
else:
result = cppName & "<"
for i in 1 .. typ.len-2:
if i > 1: result.add(", ")
if i > 1: result.add(" COMMA ")
result.add(getTypeDescAux(m, typ.sons[i], check))
result.add("> ")
# always call for sideeffects:
@@ -673,16 +703,13 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
else: getTupleDesc(m, t, result, check)
if not isImportedType(t): add(m.s[cfsTypes], recdesc)
of tySet:
case int(getSize(t))
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):
addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
result = getTypeName(t.lastSon) & "Set"
idTablePut(m.typeCache, t, result)
if not isImportedType(t):
let s = int(getSize(t))
case s
of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
[result, rope(getSize(t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
tyIter, tyTypeDesc:
@@ -704,7 +731,7 @@ type
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc
var check = initIntSet()
result = getTempName()
result = getTempName(m)
var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t):
@@ -739,7 +766,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope =
genCLineDir(result, prc.info)
# using static is needed for inline procs
if lfExportLib in prc.loc.flags:
if m.isHeaderFile:
if isHeaderFile in m.flags:
result.add "N_LIB_IMPORT "
else:
result.add "N_LIB_EXPORT "
@@ -819,7 +846,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
if L == 1:
genObjectFields(m, typ, n.sons[0], expr)
elif L > 0:
var tmp = getTempName()
var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1):
var tmp2 = getNimNode(m)
@@ -891,7 +918,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
var expr = getNimNode(m)
var length = sonsLen(typ)
if length > 0:
var tmp = getTempName()
var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
for i in countup(0, length - 1):
var a = typ.sons[i]
@@ -915,7 +942,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
# anyway. We generate a cstring array and a loop over it. Exceptional
# positions will be reset after the loop.
genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName()
var nodePtrs = getTempName(m)
var length = sonsLen(typ.n)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
[nodePtrs, rope(length)])
@@ -935,8 +962,8 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
if field.position != i or tfEnumHasHoles in typ.flags:
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true
var enumArray = getTempName()
var counter = getTempName()
var enumArray = getTempName(m)
var counter = getTempName(m)
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])
@@ -1004,9 +1031,12 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
[result, rope(typeToString(t))])
return "(&".rope & result & ")".rope
case t.kind
of tyEmpty: result = rope"0"
of tyEmpty, tyVoid: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, t, result, rope"0")
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0")

View File

@@ -93,7 +93,7 @@ proc getUniqueType*(key: PType): PType =
# produced instead of ``NI``.
result = key
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
tyCString, tyNone, tyBigNum:
tyCString, tyNone, tyBigNum, tyVoid:
result = gCanonicalTypes[k]
if result == nil:
gCanonicalTypes[k] = key
@@ -188,7 +188,7 @@ proc mangle*(name: string): string =
let c = name[i]
case c
of 'A'..'Z':
add(result, c.toLower)
add(result, c.toLowerAscii)
of '_':
discard
of 'a'..'z', '0'..'9':

View File

@@ -64,8 +64,8 @@ proc isSimpleConst(typ: PType): bool =
(t.kind == tyProc and t.callConv == ccClosure)
proc useStringh(m: BModule) =
if not m.includesStringh:
m.includesStringh = true
if includesStringh notin m.flags:
incl m.flags, includesStringh
discard lists.includeStr(m.headerFiles, "<string.h>")
proc useHeader(m: BModule, sym: PSym) =
@@ -129,7 +129,7 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
if i - 1 >= start:
add(result, substr(frmt, start, i - 1))
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
ropecg(m, fmt, args)
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
@@ -215,7 +215,7 @@ proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.}
proc genProc(m: BModule, prc: PSym)
template compileToCpp(m: BModule): expr =
template compileToCpp(m: BModule): untyped =
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
include "ccgtypes.nim"
@@ -301,7 +301,8 @@ proc resetLoc(p: BProc, loc: var TLoc) =
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
let typ = skipTypes(loc.t, abstractRange)
if not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
getTypeDesc(p.module, typ))
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use memset for temporary values for performance if we can
@@ -327,10 +328,12 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = "LOC" & rope(p.labels)
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
addf(p.blocks[0].sections[cpsLocals],
"$1 $2;$n", [getTypeDesc(p.module, t), result.r])
result.k = locTemp
#result.a = - 1
result.t = getUniqueType(t)
result.t = t
#result.t = getUniqueType(t)
result.s = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
@@ -498,7 +501,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
assert(lib != nil)
if not lib.generated:
lib.generated = true
var tmp = getGlobalTempName()
var tmp = getTempName(m)
assert(lib.name == nil)
lib.name = tmp # BUGFIX: cgsym has awful side-effects
addf(m.s[cfsVars], "static void* $1;$n", [tmp])
@@ -666,7 +669,7 @@ proc genProcAux(m: BModule, prc: PSym) =
fillResult(res)
assignParam(p, res)
if skipTypes(res.typ, abstractInst).kind == tyArray:
incl(res.loc.flags, lfIndirect)
#incl(res.loc.flags, lfIndirect)
res.loc.s = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1):
@@ -1009,11 +1012,11 @@ proc genInitCode(m: BModule) =
add(prc, m.postInitProc.s(cpsLocals))
add(prc, genSectionEnd(cpsLocals))
if optStackTrace in m.initProc.options and not m.frameDeclared:
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
# BUT: the generated init code might depend on a current frame, so
# declare it nevertheless:
m.frameDeclared = true
if not m.preventStackTrace:
incl m.flags, frameDeclared
if preventStackTrace notin m.flags:
var procname = makeCString(m.module.name.s)
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
@@ -1030,7 +1033,7 @@ proc genInitCode(m: BModule) =
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:
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
add(prc, deinitFrame(m.initProc))
add(prc, deinitGCFrame(m.initProc))
addf(prc, "}$N$N", [])
@@ -1059,9 +1062,8 @@ proc genModule(m: BModule, cfile: string): Rope =
result = getFileHeader(cfile)
result.add(genMergeInfo(m))
generateHeaders(m)
generateThreadLocalStorage(m)
generateHeaders(m)
for i in countup(cfsHeaders, cfsProcs):
add(result, genSectionStart(i))
add(result, m.s[i])
@@ -1083,6 +1085,7 @@ proc initProcOptions(m: BModule): TOptions =
proc rawNewModule(module: PSym, filename: string): BModule =
new(result)
result.tmpBase = rope("T" & $hashOwner(module) & "_")
initLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
result.declaredProtos = initIntSet()
@@ -1099,12 +1102,12 @@ proc rawNewModule(module: PSym, filename: string): BModule =
initNodeTable(result.dataCache)
result.typeStack = @[]
result.forwardedProcs = @[]
result.typeNodesName = getTempName()
result.nimTypesName = getTempName()
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
# no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags:
result.preventStackTrace = true
incl result.flags, preventStackTrace
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
@@ -1125,11 +1128,13 @@ proc resetModule*(m: BModule) =
initNodeTable(m.dataCache)
m.typeStack = @[]
m.forwardedProcs = @[]
m.typeNodesName = getTempName()
m.nimTypesName = getTempName()
m.preventStackTrace = sfSystemModule in m.module.flags
m.typeNodesName = getTempName(m)
m.nimTypesName = getTempName(m)
if sfSystemModule in m.module.flags:
incl m.flags, preventStackTrace
else:
excl m.flags, preventStackTrace
nullify m.s
m.usesThreadVars = false
m.typeNodes = 0
m.nimTypes = 0
nullify m.extensionLoaders
@@ -1174,7 +1179,7 @@ proc myOpen(module: PSym): PPassContext =
let f = if headerFile.len > 0: headerFile else: gProjectFull
generatedHeader = rawNewModule(module,
changeFileExt(completeCFilePath(f), hExt))
generatedHeader.isHeaderFile = true
incl generatedHeader.flags, isHeaderFile
proc writeHeader(m: BModule) =
var result = getCopyright(m.filename)
@@ -1306,7 +1311,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
registerModuleToMain(m.module)
if sfMainModule in m.module.flags:
m.objHasKidsValid = true
incl m.flags, objHasKidsValid
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genMainProc(m)

View File

@@ -15,7 +15,7 @@ import
from msgs import TLineInfo
type
TLabel* = Rope # 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
@@ -89,28 +89,32 @@ 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*: Rope # the struct {} we put the GC markers into
gcFrameType*: Rope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType]
Codegenflag* = enum
preventStackTrace, # true if stack traces need to be prevented
usesThreadVars, # true if the module uses a thread var
frameDeclared, # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile, # C source file is the header file
includesStringh, # C source file already includes ``<string.h>``
objHasKidsValid # whether we can rely on tfObjHasKids
TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file
flags*: set[Codegenflag]
module*: PSym
filename*: string
s*: TCFileSections # sections of the C file
preventStackTrace*: bool # true if stack traces need to be prevented
usesThreadVars*: bool # true if the module uses a thread var
frameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile*: bool # C source file is the header file
includesStringh*: bool # C source file already includes ``<string.h>``
objHasKidsValid*: bool # whether we can rely on tfObjHasKids
cfilename*: string # filename of the module (including path,
# without extension)
tmpBase*: Rope # base for temp identifier generation
typeCache*: TIdTable # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: IntSet # needed for generating type information
typeInfoMarker*: IntSet # needed for generating type information
initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before the init proc

View File

@@ -63,19 +63,25 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
while true:
aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {tyGenericInst})
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}:
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(aa, bb):
if aa.kind == tyObject and result != Invalid: result = Yes
if aa.kind == tyObject and result != Invalid:
result = Yes
elif aa.kind == tyObject and bb.kind == tyObject:
let diff = inheritanceDiff(bb, aa)
if diff < 0:
if result != Invalid: result = Yes
if result != Invalid:
result = Yes
else:
return No
elif diff != high(int):
result = Invalid
else:
return No
else:
return No
@@ -181,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb)
if (d != high(int)):
if (d != high(int)) and d != 0:
return d
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =

View File

@@ -12,7 +12,7 @@
# We do this here before the 'import' statement so 'defined' does not get
# confused with 'TGCMode.gcGenerational' etc.
template bootSwitch(name, expr, userString: expr): expr =
template bootSwitch(name, expr, userString) =
# Helper to build boot constants, for debugging you can 'echo' the else part.
const name = if expr: " " & userString else: ""
@@ -158,7 +158,7 @@ var
enableNotes: TNoteKinds
disableNotes: TNoteKinds
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off"
var i = 0
@@ -181,10 +181,13 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
case whichKeyword(substr(arg, i))
of wOn:
incl(gNotes, n)
incl(gMainPackageNotes, n)
incl(enableNotes, n)
of wOff:
excl(gNotes, n)
excl(gMainPackageNotes, n)
incl(disableNotes, n)
excl(ForeignPackageNotes, n)
else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processCompile(filename: string) =
@@ -213,6 +216,16 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
of "size": result = contains(gOptions, optOptimizeSize)
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
of "verbosity": result = $gVerbosity == arg
of "app":
case arg.normalize
of "gui": result = contains(gGlobalOptions, optGenGuiApp)
of "console": result = not contains(gGlobalOptions, optGenGuiApp)
of "lib": result = contains(gGlobalOptions, optGenDynLib) and
not contains(gGlobalOptions, optGenGuiApp)
of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
not contains(gGlobalOptions, optGenGuiApp)
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
else: invalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool =
@@ -253,20 +266,18 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false,
cfginfo = unknownLineInfo()): string =
proc processPath(path: string, info: TLineInfo,
notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or
'$' in path or path[0] == '.':
path
else:
options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
"nim", getPrefixDir(),
"lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()),
"config", cfginfo.toFullPath().splitFile().dir,
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
try:
result = pathSubs(p, info.toFullPath().splitFile().dir)
except ValueError:
localError(info, "invalid path: " & p)
result = p
proc trackDirty(arg: string, info: TLineInfo) =
var a = arg.split(',')
@@ -307,19 +318,22 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
case switch.normalize
of "path", "p":
expectArg(switch, arg, pass, info)
addPath(processPath(arg, cfginfo=info), info)
addPath(processPath(arg, info), info)
of "nimblepath", "babelpath":
# keep the old name for compat
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
expectArg(switch, arg, pass, info)
let path = processPath(arg, notRelativeToProj=true)
let path = processPath(arg, info, notRelativeToProj=true)
nimblePath(path, info)
of "nonimblepath", "nobabelpath":
expectNoArg(switch, arg, pass, info)
options.gNoNimblePath = true
options.lazyPaths.head = nil
options.lazyPaths.tail = nil
options.lazyPaths.counter = 0
of "excludepath":
expectArg(switch, arg, pass, info)
let path = processPath(arg)
let path = processPath(arg, info)
lists.excludePath(options.searchPaths, path)
lists.excludePath(options.lazyPaths, path)
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
@@ -328,7 +342,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
lists.excludePath(options.lazyPaths, strippedPath)
of "nimcache":
expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg, true)
options.nimcacheDir = processPath(arg, info, true)
of "out", "o":
expectArg(switch, arg, pass, info)
options.outFile = arg
@@ -339,7 +353,11 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
discard "allow for backwards compatibility, but don't do anything"
of "define", "d":
expectArg(switch, arg, pass, info)
defineSymbol(arg)
if {':', '='} in arg:
splitSwitch(arg, key, val, pass, info)
defineSymbol(key, val)
else:
defineSymbol(arg)
of "undef", "u":
expectArg(switch, arg, pass, info)
undefSymbol(arg)
@@ -407,6 +425,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info)
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
of "debugger":
case arg.normalize
@@ -493,13 +512,13 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
of "clibdir":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLibs.add arg.processPath
if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info)
of "clib":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
of "header":
headerFile = arg
incl(gGlobalOptions, optGenIndex)
@@ -540,6 +559,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
gNotes = NotesVerbosity[gVerbosity]
incl(gNotes, enableNotes)
excl(gNotes, disableNotes)
gMainPackageNotes = gNotes
of "parallelbuild":
expectArg(switch, arg, pass, info)
gNumberOfProcessors = parseInt(arg)
@@ -572,7 +592,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
of "lib":
expectArg(switch, arg, pass, info)
libpath = processPath(arg, notRelativeToProj=true)
libpath = processPath(arg, info, notRelativeToProj=true)
of "putenv":
expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info)

View File

@@ -19,8 +19,8 @@ var gSymbols: StringTableRef
const
catNone = "false"
proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"
proc defineSymbol*(symbol: string, value: string = "true") =
gSymbols[symbol] = value
proc undefSymbol*(symbol: string) =
gSymbols[symbol] = catNone
@@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool =
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
proc lookupSymbol*(symbol: string): string =
result = if isDefined(symbol): gSymbols[symbol] else: nil
proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
iterator definedSymbolNames*: string =
for key, val in pairs(gSymbols):
if val != catNone: yield key
@@ -93,3 +98,4 @@ proc initDefines*() =
defineSymbol("nimtypedescfixed")
defineSymbol("nimKnowsNimvm")
defineSymbol("nimArrIdx")
defineSymbol("nimImmediateDeprecated")

81
compiler/debuginfo.nim Normal file
View File

@@ -0,0 +1,81 @@
#
#
# The Nim Compiler
# (c) Copyright 2016 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## The compiler can generate debuginfo to help debuggers in translating back from C/C++/JS code
## to Nim. The data structure has been designed to produce something useful with Nim's marshal
## module.
type
FilenameHash* = uint32
FilenameMapping* = object
package*, file*: string
mangled*: FilenameHash
EnumDesc* = object
size*: int
owner*: FilenameHash
id*: int
name*: string
values*: seq[(string, int)]
DebugInfo* = object
version*: int
files*: seq[FilenameMapping]
enums*: seq[EnumDesc]
conflicts*: bool
proc sdbmHash(hash: FilenameHash, c: char): FilenameHash {.inline.} =
return FilenameHash(c) + (hash shl 6) + (hash shl 16) - hash
proc sdbmHash(package, file: string): FilenameHash =
template `&=`(x, c) = x = sdbmHash(x, c)
result = 0
for i in 0..<package.len:
result &= package[i]
result &= '.'
for i in 0..<file.len:
result &= file[i]
proc register*(self: var DebugInfo; package, file: string): FilenameHash =
result = sdbmHash(package, file)
for f in self.files:
if f.mangled == result:
if f.package == package and f.file == file: return
self.conflicts = true
break
self.files.add(FilenameMapping(package: package, file: file, mangled: result))
proc hasEnum*(self: DebugInfo; ename: string; id: int; owner: FilenameHash): bool =
for en in self.enums:
if en.owner == owner and en.name == ename and en.id == id: return true
proc registerEnum*(self: var DebugInfo; ed: EnumDesc) =
self.enums.add ed
proc init*(self: var DebugInfo) =
self.version = 1
self.files = @[]
self.enums = @[]
var gDebugInfo*: DebugInfo
debuginfo.init gDebugInfo
import marshal, streams
proc writeDebugInfo*(self: var DebugInfo; file: string) =
let s = newFileStream(file, fmWrite)
store(s, self)
s.close
proc writeDebugInfo*(file: string) = writeDebugInfo(gDebugInfo, file)
proc loadDebugInfo*(self: var DebugInfo; file: string) =
let s = newFileStream(file, fmRead)
load(s, self)
s.close
proc loadDebugInfo*(file: string) = loadDebugInfo(gDebugInfo, file)

View File

@@ -14,7 +14,7 @@
import
ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2, json, xmltree, cgi, typesrenderer
importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
type
TSections = array[TSymKind, Rope]
@@ -25,9 +25,32 @@ type
indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
jArray: JsonNode
types: TStrTable
PDoc* = ref TDocumentor ## Alias to type less.
proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
for i in 0..<safeLen(n):
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
let params = p.ast.sons[paramsPos]
# first check the first parameter, then the return type,
# then the other parameter:
template check(i) =
result = whichType(d, params[i])
if result != nil: return result
if params.len > 1: check(1)
if params.len > 0: check(0)
for i in 2..<params.len: check(i)
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind:
@@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
result.jArray = newJArray()
initStrTable result.types
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: addf(dest, xml, args)
@@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`")
of nkOpenSymChoice, nkClosedSymChoice:
result = getName(d, n[0], splitAfter)
else:
internalError(n.info, "getName()")
result = ""
proc getNameIdent(n: PNode): PIdent =
case n.kind
of nkPostfix: result = getNameIdent(n.sons[1])
of nkPragmaExpr: result = getNameIdent(n.sons[0])
of nkSym: result = n.sym.name
of nkIdent: result = n.ident
of nkAccQuoted:
var r = ""
for i in 0.. <n.len: r.add(getNameIdent(n[i]).s)
result = getIdent(r)
of nkOpenSymChoice, nkClosedSymChoice:
result = getNameIdent(n[0])
else:
result = nil
proc getRstName(n: PNode): PRstNode =
case n.kind
of nkPostfix: result = getRstName(n.sons[1])
@@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
of nkAccQuoted:
result = getRstName(n.sons[0])
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
of nkOpenSymChoice, nkClosedSymChoice:
result = getRstName(n[0])
else:
internalError(n.info, "getRstName()")
result = nil
@@ -311,7 +355,7 @@ proc docstringSummary(rstText: string): string =
## Also, we hope to not break the rst, but maybe we do. If there is any
## trimming done, an ellipsis unicode char is added.
const maxDocstringChars = 100
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
assert(rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
result = rstText.substr(2).strip
var pos = result.find('\L')
if pos > 0:
@@ -380,13 +424,27 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid:
add(result, literal)
of tkCurlyDotLe:
dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkCurlyDotRi:
dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
tkBracketDotLe, tkBracketDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))])
if k in routineKinds and nameNode.kind == nkSym:
let att = attachToType(d, nameNode.sym)
if att != nil:
dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "",
[rope esc(d.target, att.name.s)])
inc(d.id)
let
plainNameRope = rope(xmltree.escape(plainName.strip))
@@ -402,12 +460,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
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 path = n.info.toFilename.extractFilename.rope
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
["path", "line"], [path, rope($n.info.line)])
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
["path", "line", "url"], [n.info.toFilename.rope,
["path", "line", "url"], [path,
rope($n.info.line), urlRope])])
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
@@ -431,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary))
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
if not isVisible(nameNode): return
var
name = getName(d, nameNode)
@@ -441,8 +500,8 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
result = %{ "name": %name, "type": %($k) }
result = %{ "name": %name, "type": %($k), "line": %n.info.line,
"col": %n.info.col}
if comm != nil and comm != "":
result["description"] = %comm
if r.buf != nil:
@@ -492,46 +551,45 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: discard
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
proc add(d: PDoc; j: JsonNode) =
if j != nil: d.jArray.add j
proc generateJson*(d: PDoc, n: PNode) =
case n.kind
of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip
result = %{ "comment": %stripped }
d.add %{ "comment": %stripped, "line": %n.info.line,
"col": %n.info.col }
of nkProcDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skProc)
d.add genJsonItem(d, n, n.sons[namePos], skProc)
of nkMethodDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skMethod)
d.add genJsonItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skIterator)
d.add genJsonItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef:
result = genJSONItem(d, n, n.sons[namePos], skMacro)
d.add genJsonItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef:
result = genJSONItem(d, n, n.sons[namePos], skTemplate)
d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef:
when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skConverter)
d.add genJsonItem(d, n, n.sons[namePos], skConverter)
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
# order is always 'type var let const':
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList:
result = if jArray != nil: jArray else: newJArray()
for i in countup(0, sonsLen(n) - 1):
var r = generateJson(d, n.sons[i], result)
if r != nil:
result.add(r)
generateJson(d, n.sons[i])
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
discard generateJson(d, lastSon(n.sons[0]), jArray)
if not checkForFalse(n.sons[0].sons[0]):
generateJson(d, lastSon(n.sons[0]))
else: discard
proc genSection(d: PDoc, kind: TSymKind) =
@@ -593,12 +651,36 @@ proc generateIndex*(d: PDoc) =
writeIndexFile(d[], splitFile(options.outFile).dir /
splitFile(d.filename).name & IndexExt)
proc getOutFile2(filename, ext, dir: string): string =
if gWholeProject:
let d = if options.outFile != "": options.outFile else: dir
createDir(d)
result = d / changeFileExt(filename, ext)
else:
result = getOutFile(filename, ext)
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d)
if optStdout in gGlobalOptions:
writeRope(stdout, content)
else:
writeRope(content, getOutFile(filename, outExt), useWarning)
writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
proc writeOutputJson*(d: PDoc, filename, outExt: string,
useWarning = false) =
let content = %*{"orig": d.filename,
"nimble": getPackageName(d.filename),
"entries": d.jArray}
if optStdout in gGlobalOptions:
write(stdout, $content)
else:
var f: File
if open(f, getOutFile2(splitFile(filename).name,
outExt, "jsondocs"), fmWrite):
write(f, $content)
close(f)
else:
discard "fixme: error report"
proc commandDoc*() =
var ast = parseFile(gProjectMainIdx)
@@ -629,18 +711,19 @@ proc commandRst2TeX*() =
splitter = "\\-"
commandRstAux(gProjectFull, TexExt)
proc commandJSON*() =
proc commandJson*() =
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true
var json = generateJson(d, ast)
var content = rope(pretty(json))
generateJson(d, ast)
let json = d.jArray
let content = rope(pretty(json))
if optStdout in gGlobalOptions:
writeRope(stdout, content)
else:
echo getOutFile(gProjectFull, JsonExt)
#echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc commandBuildIndex*() =

View File

@@ -19,21 +19,36 @@ type
module: PSym
PGen = ref TGen
proc close(p: PPassContext, n: PNode): PNode =
template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
if gWholeProject or sfMainModule in g.module.flags:
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
if (g.module.owner.id == gMainPackageId and gWholeProject) or
sfMainModule in g.module.flags:
body
try:
generateIndex(g.doc)
except IOError:
discard
proc close(p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
proc closeJson(p: PPassContext, n: PNode): PNode =
closeImpl:
writeOutputJson(g.doc, g.module.filename, ".json", useWarning)
proc processNode(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
generateDoc(g.doc, n)
proc processNodeJson(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
generateJson(g.doc, n)
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
@@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext =
result = g
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson,
close = closeJson)
proc finishDoc2Pass*(project: string) =
discard

View File

@@ -59,7 +59,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
var totalParams = case n.kind
@@ -75,11 +75,11 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
# their bodies. We could try to fix this, but it may be
# wiser to just deprecate immediate templates and macros
# now that we have working untyped parameters.
genericParams = if sfImmediate in s.flags: 0
genericParams = if sfImmediate in s.flags or fromHlo: 0
else: s.ast[genericParamsPos].len
expectedRegularParams = <s.typ.len
givenRegularParams = totalParams - genericParams
if givenRegularParams < 0: givenRegularParams = 0
if totalParams > expectedRegularParams + genericParams:
globalError(n.info, errWrongNumberOfArguments)
@@ -104,14 +104,14 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
var evalTemplateCounter* = 0
# to prevent endless recursion in templates instantiation
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
globalError(n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl)
var args = evalTemplateArgs(n, tmpl, fromHlo)
var ctx: TemplCtx
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner

View File

@@ -16,6 +16,8 @@ import
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
securehash, streams
from debuginfo import writeDebugInfo
type
TSystemCC* = enum
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
@@ -59,7 +61,7 @@ type
# When adding new compilers, the cmake sources could be a good reference:
# http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
template compiler(name, settings: untyped): untyped =
proc name: TInfoCC {.compileTime.} = settings
# GNU C and C++ Compiler
@@ -736,6 +738,8 @@ proc callCCompiler*(projectfile: string) =
if not noAbsolutePaths():
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
if optCDebug in gGlobalOptions:
writeDebugInfo(exefile.changeFileExt("ndb"))
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
@@ -750,7 +754,7 @@ proc callCCompiler*(projectfile: string) =
"lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions:
execExternalProgram(linkCmd,
if gVerbosity > 1: hintExecuting else: hintLinking)
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
else:
linkCmd = ""
if optGenScript in gGlobalOptions:

View File

@@ -728,12 +728,12 @@ proc simpleSlice*(a, b: PNode): BiggestInt =
result = -1
template isMul(x): expr = x.getMagic in someMul
template isDiv(x): expr = x.getMagic in someDiv
template isAdd(x): expr = x.getMagic in someAdd
template isSub(x): expr = x.getMagic in someSub
template isVal(x): expr = x.kind in {nkCharLit..nkUInt64Lit}
template isIntVal(x, y): expr = x.intVal == y
template isMul(x): untyped = x.getMagic in someMul
template isDiv(x): untyped = x.getMagic in someDiv
template isAdd(x): untyped = x.getMagic in someAdd
template isSub(x): untyped = x.getMagic in someSub
template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit}
template isIntVal(x, y): untyped = x.intVal == y
import macros
@@ -776,8 +776,8 @@ proc isMinusOne(n: PNode): bool =
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
proc ple(m: TModel; a, b: PNode): TImplication =
template `<=?`(a,b): expr = ple(m,a,b) == impYes
template `>=?`(a,b): expr = ple(m, nkIntLit.newIntNode(b), a) == impYes
template `<=?`(a,b): untyped = ple(m,a,b) == impYes
template `>=?`(a,b): untyped = ple(m, nkIntLit.newIntNode(b), a) == impYes
# 0 <= 3
if a.isValue and b.isValue:

View File

@@ -24,7 +24,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
of skMacro:
result = semMacroExpr(c, n, orig, s)
of skTemplate:
result = semTemplateExpr(c, n, s)
result = semTemplateExpr(c, n, s, {efFromHlo})
else:
result = semDirectOp(c, n, {})
if optHints in gOptions and hintPattern in gNotes:

View File

@@ -11,7 +11,7 @@
import idents, strutils, os, options
var gFrontEndId, gBackendId*: int
var gFrontEndId*: int
const
debugIds* = false
@@ -30,10 +30,6 @@ proc getID*(): int {.inline.} =
result = gFrontEndId
inc(gFrontEndId)
proc backendId*(): int {.inline.} =
result = gBackendId
inc(gBackendId)
proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1)
@@ -49,7 +45,6 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
f.writeLine($gFrontEndId)
f.writeLine($gBackendId)
f.close()
proc loadMaxIds*(project: string) =
@@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) =
if f.readLine(line):
var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId)
gBackendId = max(gBackendId, backEndId)
f.close()

View File

@@ -22,7 +22,11 @@ proc getModuleName*(n: PNode): string =
# The proc won't perform any checks that the path is actually valid
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = unixToNativePath(n.strVal)
try:
result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
except ValueError:
localError(n.info, "invalid path: " & n.strVal)
result = n.strVal
of nkIdent:
result = n.ident.s
of nkSym:
@@ -172,7 +176,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[i])
if m != nil:
# ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m) # add symbol to symbol table of module
addDecl(c, m, n.info) # add symbol to symbol table of module
importAllSymbolsExcept(c, m, emptySet)
#importForwarded(c, m.ast, emptySet)
@@ -182,7 +186,7 @@ proc evalFrom(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
addDecl(c, m, n.info) # add symbol to symbol table of module
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind != nkNilLit:
importSymbol(c, n.sons[i], m)
@@ -193,7 +197,7 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
addDecl(c, m, n.info) # add symbol to symbol table of module
var exceptSet = initIntSet()
for i in countup(1, sonsLen(n) - 1):
let ident = lookups.considerQuotedIdent(n.sons[i])

View File

@@ -8,7 +8,7 @@ Platforms: """
windows: i386;amd64
linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64
netbsd: i386;amd64
openbsd: i386;amd64
@@ -48,8 +48,8 @@ Start: "doc/overview.html"
[Other]
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "makefile"
Files: "*.ini"
Files: "koch.nim"
Files: "install_nimble.nims"
Files: "icons/nim.ico"
Files: "icons/nim.rc"
@@ -60,176 +60,26 @@ Files: "icons/koch.rc"
Files: "icons/koch.res"
Files: "icons/koch_icon.o"
Files: "compiler/readme.txt"
Files: "compiler/installer.ini"
Files: "compiler/*.cfg"
Files: "compiler/*.nim"
Files: "doc/*.txt"
Files: "doc/manual/*.txt"
Files: "doc/*.nim"
Files: "doc/*.cfg"
Files: "compiler/nimfix/*.nim"
Files: "compiler/nimfix/*.cfg"
Files: "compiler/nimsuggest/*.nim"
Files: "compiler/nimsuggest/*.cfg"
Files: "compiler/plugins/locals/*.nim"
Files: "compiler/plugins/*.nim"
Files: "tools/*.nim"
Files: "tools/*.cfg"
Files: "tools/*.tmpl"
Files: "tools/niminst/*.nim"
Files: "tools/niminst/*.cfg"
Files: "tools/niminst/*.tmpl"
Files: "tools/niminst/*.nsh"
Files: "compiler"
Files: "doc"
Files: "tools"
Files: "web/website.ini"
Files: "web/ticker.html"
Files: "web/*.nim"
Files: "web/*.txt"
Files: "web/*.rst"
Files: "web/*.csv"
Files: "web/news/*.rst"
Files: "bin/nimblepkg/*.nim"
Files: "bin/nimblepkg/*.cfg"
[Lib]
Files: "lib/nimbase.h"
Files: "lib/*.nim"
Files: "lib/*.cfg"
Files: "lib/*.nimble"
Files: "lib/system/*.nim"
Files: "lib/core/*.nim"
Files: "lib/pure/*.nim"
Files: "lib/pure/*.cfg"
Files: "lib/pure/collections/*.nim"
Files: "lib/pure/concurrency/*.nim"
Files: "lib/pure/unidecode/*.nim"
Files: "lib/pure/concurrency/*.cfg"
Files: "lib/impure/*.nim"
Files: "lib/impure/nre/private/*.nim"
Files: "lib/wrappers/*.nim"
Files: "lib/arch/*.nim"
Files: "lib/wrappers/readline/*.nim"
Files: "lib/wrappers/linenoise/*.nim"
Files: "lib/wrappers/linenoise/*.c"
Files: "lib/wrappers/linenoise/*.h"
Files: "lib/windows/*.nim"
Files: "lib/posix/*.nim"
Files: "lib/js/*.nim"
Files: "lib/packages/docutils/*.nim"
Files: "lib/deprecated/core/*.nim"
Files: "lib/deprecated/pure/*.nim"
Files: "lib/deprecated/pure/*.cfg"
Files: "lib"
[Other]
Files: "examples/*.nim"
Files: "examples/c++iface/*.nim"
Files: "examples/objciface/*.nim"
Files: "examples/cross_calculator/"
Files: "examples"
#Files: "dist/nimble"
Files: "examples/*.html"
Files: "examples/*.txt"
Files: "examples/*.cfg"
Files: "examples/*.tmpl"
Files: "tests/actiontable/*.nim"
Files: "tests/alias/*.nim"
Files: "tests/ambsym/*.nim"
Files: "tests/array/*.nim"
Files: "tests/assign/*.nim"
Files: "tests/astoverload/*.nim"
Files: "tests/async/*.nim"
Files: "tests/benchmarks/*.nim"
Files: "tests/bind/*.nim"
Files: "tests/borrow/*.nim"
Files: "tests/casestmt/*.nim"
Files: "tests/ccgbugs/*.nim"
Files: "tests/clearmsg/*.nim"
Files: "tests/closure/*.nim"
Files: "tests/cnstseq/*.nim"
Files: "tests/collections/*.nim"
Files: "tests/compiles/*.nim"
Files: "tests/concat/*.nim"
Files: "tests/concepts/*.nim"
Files: "tests/constr/*.nim"
Files: "tests/constraints/*.nim"
Files: "tests/controlflow/*.nim"
Files: "tests/converter/*.nim"
Files: "tests/cpp/*.nim"
Files: "tests/defaultprocparam/*.nim"
Files: "tests/deprecated/*.nim"
Files: "tests/destructor/*.nim"
Files: "tests/dir with space/*.nim"
Files: "tests/discard/*.nim"
Files: "tests/distinct/*.nim"
Files: "tests/dll/*.nim"
Files: "tests/effects/*.nim"
Files: "tests/enum/*.nim"
Files: "tests/exception/*.nim"
Files: "tests/exprs/*.nim"
Files: "tests/fields/*.nim"
Files: "tests/float/*.nim"
Files: "tests/friends/*.nim"
Files: "tests/gc/*.nim"
Files: "tests/generics/*.nim"
Files: "tests/gensym/*.nim"
Files: "tests/global/*.nim"
Files: "tests/implicit/*.nim"
Files: "tests/init/*.nim"
Files: "tests/iter/*.nim"
Files: "tests/js/*.nim"
Files: "tests/js/*.cfg"
Files: "tests/let/*.nim"
Files: "tests/lexer/*.nim"
Files: "tests/lookups/*.nim"
Files: "tests/macros/*.nim"
Files: "tests/magics/*.nim"
Files: "tests/metatype/*.nim"
Files: "tests/method/*.nim"
Files: "tests/misc/*.nim"
Files: "tests/modules/*.nim"
Files: "tests/namedparams/*.nim"
Files: "tests/notnil/*.nim"
Files: "tests/objects/*.nim"
Files: "tests/objvariant/*.nim"
Files: "tests/openarray/*.nim"
Files: "tests/osproc/*.nim"
Files: "tests/overflw/*.nim"
Files: "tests/overload/*.nim"
Files: "tests/parallel/*.nim"
Files: "tests/parallel/*.cfg"
Files: "tests/parser/*.nim"
Files: "tests/pragmas/*.nim"
Files: "tests/proc/*.nim"
Files: "tests/procvar/*.nim"
Files: "tests/range/*.nim"
Files: "tests/rodfiles/*.nim"
Files: "tests/seq/*.nim"
Files: "tests/sets/*.nim"
Files: "tests/showoff/*.nim"
Files: "tests/specialops/*.nim"
Files: "tests/stdlib/*.nim"
Files: "tests/system/*.nim"
Files: "tests/template/*.nim"
Files: "tests/testament/*.nim"
Files: "tests/testdata/*.csv"
Files: "tests/testdata/*.html"
Files: "tests/testdata/*.json"
Files: "tests/testdata/*.txt"
Files: "tests/testdata/*.xml"
Files: "tests/threads/*.nim"
Files: "tests/threads/*.cfg"
Files: "tests/trmacros/*.nim"
Files: "tests/tuples/*.nim"
Files: "tests/typerel/*.nim"
Files: "tests/types/*.nim"
Files: "tests/usingstmt/*.nim"
Files: "tests/varres/*.nim"
Files: "tests/varstmt/*.nim"
Files: "tests/vm/*.nim"
Files: "tests/readme.txt"
Files: "tests/testament/css/*.css"
Files: "tests/testament/*.cfg"
Files: "lib/pure/unidecode/unidecode.dat"
Files: "tests"
[Windows]
Files: "bin/nim.exe"
@@ -249,7 +99,7 @@ BinPath: r"bin;dist\mingw\bin;dist"
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
Download: r"Support DLL's|bin|nim_dlls.zip|479|http://nim-lang.org/download/dlls.zip"
Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe"
Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
; for now only NSIS supports optional downloads
[UnixBin]
@@ -279,3 +129,7 @@ buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nim Compiler"
licenses: "bin/nim,MIT;lib/*,MIT;"
[nimble]
pkgName: "compiler"
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt"

View File

@@ -8,7 +8,7 @@
#
# This is the JavaScript code generator.
# Soon also a PHP code generator. ;-)
# Also a PHP code generator. ;-)
discard """
The JS code generator contains only 2 tricks:
@@ -48,6 +48,7 @@ type
etyNull, # null type
etyProc, # proc type
etyBool, # bool type
etySeq, # Nim seq or string type
etyInt, # JavaScript's int
etyFloat, # JavaScript's float
etyString, # JavaScript's string
@@ -71,7 +72,7 @@ type
isLoop: bool # whether it's a 'block' or 'while'
TGlobals = object
typeInfo, code: Rope
typeInfo, constants, code: Rope
forwarded: seq[PSym]
generatedSyms: IntSet
typeInfoGenerated: IntSet
@@ -94,7 +95,7 @@ type
up: PProc # up the call chain; required for closure support
declaredGlobals: IntSet
template `|`(a, b: expr): expr {.immediate, dirty.} =
template `|`(a, b: untyped): untyped {.dirty.} =
(if p.target == targetJS: a else: b)
proc newGlobals(): PGlobals =
@@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table
of tyString, tySequence: result = etyInt # little hack to get right semantics
of tyString, tySequence: result = etySeq
of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
tyVarargs:
result = etyObject
of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
result = etyNone
of tyStatic:
if t.n != nil: result = mapType(lastSon t)
else: result = etyNone
of tyProc: result = etyProc
of tyCString: result = etyString
@@ -237,7 +241,7 @@ proc useMagic(p: PProc, name: string) =
internalAssert s.kind in {skProc, skMethod, skConverter}
if not p.g.generatedSyms.containsOrIncl(s.id):
let code = genProc(p, s)
add(p.g.code, code)
add(p.g.constants, code)
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
@@ -359,8 +363,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 != $2)", "($1 != $2)"], # Xor
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 == $2)", "($1 == $2)"], # EqProc
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
@@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
return
let xtyp = mapType(p, x.typ)
var xtyp = mapType(p, x.typ)
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
gen(p, x.sons[0], a)
@@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
gen(p, y, b)
# we don't care if it's an etyBaseIndex (global) of a string, it's
# still a string that needs to be copied properly:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
xtyp = etySeq
case xtyp
of etySeq:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
of etyObject:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
@@ -981,7 +996,7 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
r.res = "nimAt($1, $2)" % [r.address, r.res]
elif ty.kind in {tyString, tyCString}:
# XXX this needs to be more like substr($1,$2)
r.res = "ord($1[$2])" % [r.address, r.res]
r.res = "ord(@$1[$2])" % [r.address, r.res]
else:
r.res = "$1[$2]" % [r.address, r.res]
else:
@@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n.sons[0], r)
of nkHiddenDeref:
gen(p, n.sons[0].sons[0], r)
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
proc thisParam(p: PProc; typ: PType): PType =
@@ -1215,11 +1232,13 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
genArgNoParam(p, it, r)
else:
genArg(p, it, paramType.sym, r)
inc generated
proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
r: var TCompRes) =
var i = 0
var j = 1
r.kind = resExpr
while i < pat.len:
case pat[i]
of '@':
@@ -1233,31 +1252,43 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
genOtherArg(p, n, j, typ, generated, r)
inc j
inc i
of '\31':
# unit separator
add(r.res, "#")
inc i
of '\29':
# group separator
add(r.res, "@")
inc i
else:
let start = i
while i < pat.len:
if pat[i] notin {'@', '#'}: inc(i)
if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
else: break
if i - 1 >= start:
add(r.res, substr(pat, start, i - 1))
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
# don't call '$' here for efficiency:
let pat = n.sons[0].sym.loc.r.data
internalAssert pat != nil
if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
genPatternCall(p, n, pat, typ, r)
return
gen(p, n.sons[1], r)
if r.typ == etyBaseIndex:
if r.address == nil:
globalError(n.info, "cannot invoke with infix syntax")
r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.typ = etyNone
add(r.res, "." | "->")
let f = n[0].sym
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
if sfInfixCall in f.flags:
let pat = n.sons[0].sym.loc.r.data
internalAssert pat != nil
if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
genPatternCall(p, n, pat, typ, r)
return
if n.len != 1:
gen(p, n.sons[1], r)
if r.typ == etyBaseIndex:
if r.address == nil:
globalError(n.info, "cannot invoke with infix syntax")
r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.typ = etyNone
add(r.res, "." | "->")
var op: TCompRes
if p.target == targetPHP:
op.kind = resCallee
@@ -1266,7 +1297,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
genArgs(p, n, r, 2)
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
if thisParam(p, n.sons[0].typ) != nil:
if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil:
genInfixCall(p, n, r)
return
if p.target == targetPHP:
@@ -1400,6 +1431,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect)
of tySequence, tyString, tyCString, tyPointer, tyProc:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
result = createVar(p, lastSon t, indirect)
else:
internalError("createVar: " & $t.kind)
result = nil
else:
internalError("createVar: " & $t.kind)
result = nil
@@ -1409,13 +1446,16 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
a: TCompRes
s: Rope
if n.kind == nkEmpty:
let mname = mangleName(v, p.target)
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
[mangleName(v, p.target), createVar(p, v.typ, isIndirect(v))])
[mname, createVar(p, v.typ, isIndirect(v))])
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
addf(p.body, "var $1_Idx = 0;$n", [ mname ])
else:
discard mangleName(v, p.target)
gen(p, n, a)
case mapType(p, v.typ)
of etyObject:
of etyObject, etySeq:
if needsNoCopy(p, n):
s = a.res
else:
@@ -1458,7 +1498,7 @@ proc genConstant(p: PProc, c: PSym) =
p.body = nil
#genLineDir(p, c.ast)
genVarInit(p, c, c.ast)
add(p.g.code, p.body)
add(p.g.constants, p.body)
p.body = oldBody
proc genNew(p: PProc, n: PNode) =
@@ -1554,8 +1594,16 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
of tyEnum, tyOrdinal:
gen(p, n.sons[1], r)
useMagic(p, "cstrToNimstr")
var offset = ""
if t.kind == tyEnum:
let firstFieldOffset = t.n.sons[0].sym.position
if firstFieldOffset < 0:
offset = "+" & $(-firstFieldOffset)
elif firstFieldOffset > 0:
offset = "-" & $firstFieldOffset
r.kind = resExpr
r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
r.res = "cstrToNimstr($1.node.sons[$2$3].name)" % [genTypeInfo(p, t), r.res, rope(offset)]
else:
# XXX:
internalError(n.info, "genRepr: Not implemented")
@@ -1645,8 +1693,11 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r)
of mLengthStr:
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
"strlen($1)")
if p.target == targetJS and n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
else:
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
"strlen($1)")
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)")
of mLengthSeq, mLengthOpenArray, mLengthArray:
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)" |
@@ -1672,8 +1723,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "")
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "")
of mSetLengthStr:
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)")
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
@@ -1683,8 +1735,31 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]")
of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)" | "isset($1[$2])")
of mInSet:
if p.target == targetJS:
binaryExpr(p, n, r, "", "($1[$2] != undefined)")
else:
let s = n.sons[1]
if s.kind == nkCurly:
var a, b, x: TCompRes
gen(p, n.sons[2], x)
r.res = rope("(")
r.kind = resExpr
for i in countup(0, sonsLen(s) - 1):
if i > 0: add(r.res, " || ")
var it = s.sons[i]
if it.kind == nkRange:
gen(p, it.sons[0], a)
gen(p, it.sons[1], b)
addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,])
else:
gen(p, it, a)
addf(r.res, "($1 == $2)", [x.res, a.res])
add(r.res, ")")
else:
binaryExpr(p, n, r, "", "isset($1[$2])")
of mNewSeq: genNewSeq(p, n)
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
of mOf: genOf(p, n, r)
of mReset: genReset(p, n)
of mEcho: genEcho(p, n, r)
@@ -1877,9 +1952,13 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
let header = generateHeader(p, prc.typ)
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast.sons[resultPos].sym
let mname = mangleName(resultSym, p.target)
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
mangleName(resultSym, p.target),
mname,
createVar(p, resultSym.typ, isIndirect(resultSym))]
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
resultAsgn.add "var $#_Idx = 0;$n" % [
mname ];
gen(p, prc.ast.sons[resultPos], a)
if mapType(p, resultSym.typ) == etyBaseIndex:
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
@@ -1983,7 +2062,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
genMagic(p, n, r)
elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
n.len >= 2:
n.len >= 1:
genInfixCall(p, n, r)
else:
genCall(p, n, r)
@@ -2131,7 +2210,7 @@ proc wholeCode*(m: BModule): Rope =
var p = newProc(globals, m, nil, m.module.options)
attachProc(p, prc)
result = globals.typeInfo & globals.code
result = globals.typeInfo & globals.constants & globals.code
proc getClassName(t: PType): Rope =
var s = t.sym

View File

@@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result)
of tyStatic:
if t.n != nil: result = genTypeInfo(p, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')

View File

@@ -716,11 +716,16 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
#localError(n.info, "internal error: closure to closure created")
# now we know better, so patch it:
n.sons[0] = x.sons[0]
n.sons[1] = x.sons[1]
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil and n[namePos].kind == nkSym:
let m = newSymNode(n[namePos].sym)
m.typ = n.typ
result = liftCapturedVars(m, owner, d, c)
of nkHiddenStdConv:
if n.len == 2:
n.sons[1] = liftCapturedVars(n[1], owner, d, c)
if n[1].kind == nkClosure: result = n[1]
else:
if owner.isIterator:
if n.kind == nkYieldStmt:

View File

@@ -138,6 +138,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
proc isNimIdentifier*(s: string): bool =
if s[0] in SymStartChars:
var i = 1
@@ -589,12 +591,29 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
of '\\':
add(tok.literal, '\\')
inc(L.bufpos)
of 'x', 'X':
of 'x', 'X', 'u', 'U':
var tp = L.buf[L.bufpos]
inc(L.bufpos)
var xi = 0
handleHexChar(L, xi)
handleHexChar(L, xi)
add(tok.literal, chr(xi))
if tp in {'u', 'U'}:
handleHexChar(L, xi)
handleHexChar(L, xi)
# inlined toUTF-8 to avoid unicode and strutils dependencies.
if xi <=% 127:
add(tok.literal, xi.char )
elif xi <=% 0x07FF:
add(tok.literal, ((xi shr 6) or 0b110_00000).char )
add(tok.literal, ((xi and ones(6)) or 0b10_0000_00).char )
elif xi <=% 0xFFFF:
add(tok.literal, (xi shr 12 or 0b1110_0000).char )
add(tok.literal, (xi shr 6 and ones(6) or 0b10_0000_00).char )
add(tok.literal, (xi and ones(6) or 0b10_0000_00).char )
else: # value is 0xFFFF
add(tok.literal, "\xef\xbf\xbf" )
else:
add(tok.literal, chr(xi))
of '0'..'9':
if matchTwoChars(L, '0', {'0'..'9'}):
lexMessage(L, warnOctalEscape)
@@ -716,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
if c == '\226' and
buf[pos+1] == '\128' and
buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or
isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos:
lexMessage(L, errInvalidToken, "")
break
inc(pos, magicIdentSeparatorRuneByteWidth)
@@ -728,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
h = h !& ord(c)
inc(pos)
of '_':
if buf[pos+1] notin SymChars:
if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
lexMessage(L, errInvalidToken, "_")
break
inc(pos)
@@ -811,10 +831,6 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
break
dec nesting
inc pos
of '\t':
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
inc(pos)
if isDoc: tok.literal.add '\t'
of CR, LF:
pos = handleCRLF(L, pos)
buf = L.buf
@@ -877,10 +893,10 @@ proc scanComment(L: var TLexer, tok: var TToken) =
inc(indent)
when defined(nimfix):
template doContinue(): expr =
template doContinue(): untyped =
buf[pos] == '#' and (col == indent or lastBackslash > 0)
else:
template doContinue(): expr =
template doContinue(): untyped =
buf[pos] == '#' and buf[pos+1] == '#'
if doContinue():
tok.literal.add "\n"
@@ -926,9 +942,9 @@ proc skip(L: var TLexer, tok: var TToken) =
break
tok.strongSpaceA = 0
when defined(nimfix):
template doBreak(): expr = buf[pos] > ' '
template doBreak(): untyped = buf[pos] > ' '
else:
template doBreak(): expr =
template doBreak(): untyped =
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
if doBreak():
tok.indent = indent
@@ -1041,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of '_':
inc(L.bufpos)
if L.buf[L.bufpos] notin SymChars:
if L.buf[L.bufpos] notin SymChars+{'_'} and not
isMagicIdentSeparatorRune(L.buf, L.bufpos):
tok.tokType = tkSymbol
tok.ident = getIdent("_")
else:
@@ -1062,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
tok.tokType = tkCharLit
of '0'..'9':
getNumber(L, tok)
let c = L.buf[L.bufpos]
if c in SymChars+{'_'}:
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
else:
if c in OpChars:
getOperator(L, tok)

View File

@@ -99,8 +99,11 @@ proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope):
result = strTableGet(scope.symbols, s)
if result != nil and result.kind in filter: return
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter: return candidate
candidate = nextIdentIter(ti, scope.symbols)
result = nil
proc errorSym*(c: PContext, n: PNode): PSym =
@@ -153,7 +156,8 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
# XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
s.typ.kind != tyGenericParam:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)
@@ -161,6 +165,10 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)
proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) =
if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(info, sym.name.s)
proc addDecl*(c: PContext, sym: PSym) =
if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s)
@@ -212,14 +220,27 @@ when defined(nimfix):
of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
else: result = x
template fixSpelling(n: PNode; ident: PIdent; op: expr) =
template fixSpelling(n: PNode; ident: PIdent; op: untyped) =
let alt = ident.altSpelling
result = op(c, alt).skipAlias(n)
if result != nil:
prettybase.replaceDeprecated(n.info, ident, alt)
return result
else:
template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
template fixSpelling(n: PNode; ident: PIdent; op: untyped) = discard
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
var err = "Error: ambiguous identifier: '" & s.name.s & "'"
var ti: TIdentIter
var candidate = initIdentIter(ti, c.importTable.symbols, s.name)
var i = 0
while candidate != nil:
if i == 0: err.add " --use "
else: err.add " or "
err.add candidate.owner.name.s & "." & candidate.name.s
candidate = nextIdentIter(ti, c.importTable.symbols)
inc i
localError(info, errGenerated, err)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
@@ -243,32 +264,36 @@ proc lookUp*(c: PContext, n: PNode): PSym =
internalError(n.info, "lookUp")
return
if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s)
errorUseQualifier(c, n.info, result)
if result.kind == skStub: loadStub(result)
type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared
checkAmbiguity, checkUndeclared, checkModule
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(n)
result = searchInScopes(c, ident).skipAlias(n)
if checkModule in flags:
result = searchInScopes(c, ident).skipAlias(n)
else:
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
if result == nil and checkUndeclared in flags:
fixSpelling(n, ident, searchInScopes)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and
contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, ident.s)
errorUseQualifier(c, n.info, result)
of nkSym:
result = n.sym
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, n.sym.name.s)
errorUseQualifier(c, n.info, n.sym)
of nkDotExpr:
result = nil
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule})
if m != nil and m.kind == skModule:
var ident: PIdent = nil
if n.sons[1].kind == nkIdent:
@@ -313,7 +338,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimDone
of nkDotExpr:
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n.sons[0])
o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule})
if o.m != nil and o.m.kind == skModule:
var ident: PIdent = nil
if n.sons[1].kind == nkIdent:

View File

@@ -471,6 +471,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
let slice = newNodeI(nkCall, n.info, 4)
slice.typ = n.typ
slice.sons[0] = newSymNode(createMagic("slice", mSlice))
slice.sons[0].typ = getSysType(tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info)
fieldB.typ = getSysType(tyInt)
objType.addField(fieldB)
@@ -577,6 +578,8 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
var fn = n.sons[0]
# templates and macros are in fact valid here due to the nature of
# the transformation:
if fn.kind == nkClosure:
localError(n.info, "closure in spawn environment is not allowed")
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj

View File

@@ -41,11 +41,15 @@ proc getSysSym*(name: string): PSym =
proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter
let id = getIdent(name)
result = initIdentIter(ti, systemModule.tab, id)
while result != nil:
if result.kind == skStub: loadStub(result)
if result.magic == m: return result
result = nextIdentIter(ti, systemModule.tab)
var r = initIdentIter(ti, systemModule.tab, id)
while r != nil:
if r.kind == skStub: loadStub(r)
if r.magic == m:
# prefer the tyInt variant:
if r.typ.sons[0].kind == tyInt: return r
result = r
r = nextIdentIter(ti, systemModule.tab)
if result != nil: return result
rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)

View File

@@ -41,14 +41,16 @@ proc commandGenDepend =
proc commandCheck =
msgs.gErrorMax = high(int) # do not stop after first error
defineSymbol("nimcheck")
semanticPasses() # use an empty backend for semantic checking only
rodPass()
compileProject()
proc commandDoc2 =
proc commandDoc2(json: bool) =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(docgen2Pass)
if json: registerPass(docgen2JsonPass)
else: registerPass(docgen2Pass)
#registerPass(cleanupPass())
compileProject()
finishDoc2Pass(gProjectName)
@@ -241,7 +243,7 @@ proc mainCommand* =
clearPasses()
gLastCmdTime = epochTime()
appendStr(searchPaths, options.libpath)
if gProjectFull.len != 0:
when false: # gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setId(100)
@@ -280,7 +282,7 @@ proc mainCommand* =
gCmd = cmdDoc
loadConfigs(DocConfig)
defineSymbol("nimdoc")
commandDoc2()
commandDoc2(false)
of "rst2html":
gCmd = cmdRst2html
loadConfigs(DocConfig)
@@ -295,7 +297,13 @@ proc mainCommand* =
loadConfigs(DocConfig)
wantMainModule()
defineSymbol("nimdoc")
commandJSON()
commandJson()
of "jsondoc2":
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
defineSymbol("nimdoc")
commandDoc2(true)
of "buildindex":
gCmd = cmdDoc
loadConfigs(DocConfig)

View File

@@ -29,12 +29,16 @@ var
gMemCacheData*: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing
gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
packageSyms: TStrTable
initStrTable(packageSyms)
proc getModule*(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx]
template hash(x: PSym): expr =
template hash(x: PSym): untyped =
gMemCacheData[x.position].hash
proc hashChanged(fileIdx: int32): bool =
@@ -45,7 +49,7 @@ proc hashChanged(fileIdx: int32): bool =
else: hashNotChanged
# echo "TESTING Hash: ", fileIdx.toFilename, " ", result
case gMemCacheData[fileIdx].hashStatus:
case gMemCacheData[fileIdx].hashStatus
of hashHasChanged:
result = true
of hashNotChanged:
@@ -90,6 +94,7 @@ proc resetAllModules* =
if gCompiledModules[i] != nil:
resetModule(i.int32)
resetPackageCache()
initStrTable(packageSyms)
# for m in cgenModules(): echo "CGEN MODULE FOUND"
proc resetAllModulesHard* =
@@ -97,6 +102,7 @@ proc resetAllModulesHard* =
gCompiledModules.setLen 0
gMemCacheData.setLen 0
magicsys.resetSysTypes()
initStrTable(packageSyms)
# XXX
#gOwners = @[]
@@ -105,12 +111,16 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
resetModule(fileIdx)
return Yes
if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile
if gFuzzyGraphChecking:
if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile
else:
# cycle detection: We claim that a cycle does no harm.
if gMemCacheData[fileIdx].needsRecompile == Probing:
return No
if optForceFullMake in gGlobalOptions or
hashChanged(fileIdx):
markDirty
if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
markDirty()
if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing
@@ -118,7 +128,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
let d = checkDepMem(dep)
if d in {Yes, Recompiled}:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty
markDirty()
gMemCacheData[fileIdx].needsRecompile = No
return No
@@ -135,8 +145,16 @@ proc newModule(fileIdx: int32): PSym =
rawMessage(errInvalidModuleName, result.name.s)
result.info = newLineInfo(fileIdx, 1, 1)
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
result.info)
let pack = getIdent(getPackageName(filename))
var packSym = packageSyms.strTableGet(pack)
if packSym == nil:
let pck = getPackageName(filename)
let pck2 = if pck.len > 0: pck else: "unknown"
packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
initStrTable(packSym.tab)
packageSyms.strTableAdd(packSym)
result.owner = packSym
result.position = fileIdx
growCache gMemCacheData, fileIdx
@@ -146,6 +164,11 @@ proc newModule(fileIdx: int32): PSym =
incl(result.flags, sfUsed)
initStrTable(result.tab)
strTableAdd(result.tab, result) # a module knows itself
let existing = strTableGet(packSym.tab, result.name)
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
# strTableIncl() for error corrections:
discard strTableIncl(packSym.tab, result)
proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
@@ -156,6 +179,9 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
#var rd = handleSymbolFile(result)
var rd: PRodReader
result.flags = result.flags + flags
if sfMainModule in result.flags:
gMainPackageId = result.owner.id
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
@@ -181,8 +207,11 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
# this is called by the semantic checking phase
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags:
localError(result.info, errAttemptToRedefine, result.name.s)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
else: ForeignPackageNotes
proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx)

View File

@@ -471,6 +471,8 @@ type
shortName*: string # short name of the module
quotedName*: Rope # cached quoted short name for codegen
# purposes
quotedFullName*: Rope # cached quoted full name for codegen
# purposes
lines*: seq[Rope] # the source code of the module
# used for better error messages and
@@ -505,7 +507,7 @@ const
warnProveField, warnProveIndex,
warnGcUnsafe,
hintSuccessX, hintPath, hintConf,
hintProcessing,
hintProcessing, hintPattern,
hintDependency,
hintExecuting, hintLinking,
hintCodeBegin, hintCodeEnd,
@@ -514,9 +516,8 @@ const
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintPath, hintConf,
hintPath,
hintDependency,
hintExecuting,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
@@ -527,6 +528,8 @@ const
InvalidFileIDX* = int32(-1)
var
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting}
filenameToIndexTbl = initTable[string, int32]()
fileInfos*: seq[TFileInfo] = @[]
systemFileIdx*: int32
@@ -561,6 +564,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
let fileName = projPath.extractFilename
result.shortName = fileName.changeFileExt("")
result.quotedName = fileName.makeCString
result.quotedFullName = fullPath.makeCString
if optEmbedOrigSrc in gGlobalOptions or true:
result.lines = @[]
@@ -616,6 +620,7 @@ var
gHintCounter*: int = 0
gWarnCounter*: int = 0
gErrorMax*: int = 1 # stop after gErrorMax errors
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
proc unknownLineInfo*(): TLineInfo =
result.line = int16(-1)
@@ -755,7 +760,7 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) =
flushFile(stderr)
macro callIgnoringStyle(theProc: typed, first: typed,
args: varargs[expr]): stmt =
args: varargs[typed]): untyped =
let typForegroundColor = bindSym"ForegroundColor".getType
let typBackgroundColor = bindSym"BackgroundColor".getType
let typStyle = bindSym"Style".getType
@@ -772,7 +777,7 @@ macro callIgnoringStyle(theProc: typed, first: typed,
typ != typTerminalCmd:
result.add(arg)
macro callStyledWriteLineStderr(args: varargs[expr]): stmt =
macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
result = newCall(bindSym"styledWriteLine")
result.add(bindSym"stderr")
for arg in children(args[0][1]):
@@ -784,7 +789,7 @@ template callWritelnHook(args: varargs[string, `$`]) =
s.add arg
writelnHook s
template styledMsgWriteln*(args: varargs[expr]) =
template styledMsgWriteln*(args: varargs[typed]) =
if not isNil(writelnHook):
callIgnoringStyle(callWritelnHook, nil, args)
elif optStdout in gGlobalOptions:
@@ -995,11 +1000,11 @@ proc internalError*(errMsg: string) =
writeContext(unknownLineInfo())
rawMessage(errInternal, errMsg)
template assertNotNil*(e: expr): expr =
template assertNotNil*(e): untyped =
if e == nil: internalError($instantiationInfo())
e
template internalAssert*(e: bool): stmt =
template internalAssert*(e: bool) =
if not e: internalError($instantiationInfo())
proc addSourceLine*(fileIdx: int32, line: string) =
@@ -1022,7 +1027,10 @@ proc sourceLine*(i: TLineInfo): Rope =
proc quotedFilename*(i: TLineInfo): Rope =
internalAssert i.fileIndex >= 0
result = fileInfos[i.fileIndex].quotedName
if optExcessiveStackTrace in gGlobalOptions:
result = fileInfos[i.fileIndex].quotedFullName
else:
result = fileInfos[i.fileIndex].quotedName
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err

View File

@@ -7,7 +7,7 @@ path:"$projectPath/.."
path:"$lib/packages/docutils"
define:booting
import:testability
#import:"$projectpath/testability"
@if windows:
cincludes: "$lib/wrappers/libffi/common"

View File

@@ -56,12 +56,12 @@ proc handleCmdLine() =
loadConfigs(DefaultConfig) # load all config files
let scriptFile = gProjectFull.changeFileExt("nims")
if fileExists(scriptFile):
runNimScript(scriptFile)
runNimScript(scriptFile, freshDefines=false)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return
elif fileExists(gProjectPath / "config.nims"):
# directory wide NimScript file
runNimScript(gProjectPath / "config.nims")
runNimScript(gProjectPath / "config.nims", freshDefines=false)
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()

View File

@@ -5,7 +5,7 @@ hint[XDeclaredButNotUsed]:off
path:"$projectPath/.."
path:"$lib/packages/docutils"
path:"../../compiler"
path:"$nim"
define:useStdoutAsStdmsg
symbol:nimfix

View File

@@ -66,7 +66,7 @@ proc beautifyName(s: string, k: TSymKind): string =
]:
result.add s[i]
else:
result.add toUpper(s[i])
result.add toUpperAscii(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
@@ -74,7 +74,7 @@ proc beautifyName(s: string, k: TSymKind): string =
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
elif '_' in s: result.add(s[i])
else: result.add toLower(s[0])
else: result.add toLowerAscii(s[0])
inc i
while i < s.len:
if s[i] == '_':
@@ -85,9 +85,9 @@ proc beautifyName(s: string, k: TSymKind): string =
result.add s[i]
else:
inc i
result.add toUpper(s[i])
result.add toUpperAscii(s[i])
elif allUpper:
result.add toLower(s[i])
result.add toLowerAscii(s[i])
else:
result.add s[i]
inc i

View File

@@ -121,7 +121,7 @@ proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
e = b
inc(e)
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
var x, y: TBitSet
toBitSet(a, x)
toBitSet(b, y)

View File

@@ -67,6 +67,8 @@ type # please make sure we have under 32 options
optIdeDebug # idetools: debug mode
optIdeTerse # idetools: use terse descriptions
optNoCppExceptions # use C exception handling even with CPP
optExcessiveStackTrace # fully qualified module filenames
TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nim's commands
# **keep binary compatible**
@@ -127,10 +129,10 @@ var
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
template compilationCachePresent*: expr =
template compilationCachePresent*: untyped =
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
template optPreserveOrigSource*: expr =
template optPreserveOrigSource*: untyped =
optEmbedOrigSrc in gGlobalOptions
const
@@ -149,6 +151,7 @@ const
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive)
gModuleOverrides* = newStringTable(modeStyleInsensitive)
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
libpath* = ""
gProjectName* = "" # holds a name like 'nim'
@@ -209,9 +212,7 @@ proc setDefaultLibpath*() =
# Special rule to support other tools (nimble) which import the compiler
# modules and make use of them.
let realNimPath = # Make sure we expand the symlink
if symlinkExists(findExe("nim")): expandSymlink(findExe("nim"))
else: findExe("nim")
let realNimPath = findExe("nim")
# Find out if $nim/../../lib/system.nim exists.
let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
if not fileExists(libpath / "system.nim") and
@@ -219,7 +220,7 @@ proc setDefaultLibpath*() =
libpath = parentNimLibPath
proc canonicalizePath*(path: string): string =
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
when not FileSystemCaseSensitive: result = path.expandFilename.toLowerAscii
else: result = path.expandFilename
proc shortenDir*(dir: string): string =
@@ -238,57 +239,26 @@ proc removeTrailingDirSep*(path: string): string =
else:
result = path
include packagehandling
proc getNimcacheDir*: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
template newPackageCache(): expr =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache()
proc resetPackageCache*() = packageCache = newPackageCache()
iterator myParentDirs(p: string): string =
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
var current = p
while true:
current = current.parentDir
if current.len == 0: break
yield current
proc getPackageName*(path: string): string =
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name
break packageSearch
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
# we also store if we didn't find anything:
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
dec parents
if parents <= 0: break
proc withPackageName*(path: string): string =
let x = path.getPackageName
if x.len == 0:
result = path
else:
let (p, file, ext) = path.splitFile
result = (p / (x & '_' & file)) & ext
proc pathSubs*(p, config: string): string =
let home = removeTrailingDirSep(os.getHomeDir())
result = unixToNativePath(p % [
"nim", getPrefixDir(),
"lib", libpath,
"home", home,
"config", config,
"projectname", options.gProjectName,
"projectpath", options.gProjectPath,
"projectdir", options.gProjectPath,
"nimcache", getNimcacheDir()])
if '~' in result:
result = result.replace("~", home)
proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
@@ -357,17 +327,25 @@ proc rawFindFile2(f: string): string =
it = PStrEntry(it.next)
result = ""
template patchModule() {.dirty.} =
if result.len > 0 and gModuleOverrides.len > 0:
let key = getPackageName(result) & "_" & splitFile(result).name
if gModuleOverrides.hasKey(key):
let ov = gModuleOverrides[key]
if ov.len > 0: result = ov
proc findFile*(f: string): string {.procvar.} =
if f.isAbsolute:
result = if f.existsFile: f else: ""
else:
result = f.rawFindFile
if result.len == 0:
result = f.toLower.rawFindFile
result = f.toLowerAscii.rawFindFile
if result.len == 0:
result = f.rawFindFile2
if result.len == 0:
result = f.toLower.rawFindFile2
result = f.toLowerAscii.rawFindFile2
patchModule()
proc findModule*(modulename, currentModule: string): string =
# returns path to module
@@ -386,6 +364,7 @@ proc findModule*(modulename, currentModule: string): string =
result = currentPath / m
if not existsFile(result):
result = findFile(m)
patchModule()
proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(')
@@ -426,10 +405,10 @@ proc binaryStrSearch*(x: openArray[string], y: string): int =
return mid
result = - 1
template nimdbg*: expr = c.module.fileIdx == gProjectMainIdx
template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
template nimdbg*: untyped = c.module.fileIdx == gProjectMainIdx
template cnimdbg*: untyped = p.module.module.fileIdx == gProjectMainIdx
template pnimdbg*: untyped = p.lex.fileIdx == gProjectMainIdx
template lnimdbg*: untyped = L.fileIdx == gProjectMainIdx
proc parseIdeCmd*(s: string): IdeCmd =
case s:

View File

@@ -0,0 +1,56 @@
#
#
# The Nim Compiler
# (c) Copyright 2016 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
iterator myParentDirs(p: string): string =
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
var current = p
while true:
current = current.parentDir
if current.len == 0: break
yield current
template newPackageCache(): untyped =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache()
proc resetPackageCache*() = packageCache = newPackageCache()
proc getPackageName*(path: string): string =
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name
break packageSearch
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
# we also store if we didn't find anything:
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
dec parents
if parents <= 0: break
proc withPackageName*(path: string): string =
let x = path.getPackageName
if x.len == 0:
result = path
else:
let (p, file, ext) = path.splitFile
result = (p / (x & '_' & file)) & ext

View File

@@ -98,7 +98,7 @@ proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
## Produce and emit a parser message to output about the token `tok`
parMessage(p, msg, prettyTok(tok))
template withInd(p: expr, body: stmt) {.immediate.} =
template withInd(p, body: untyped) =
let oldInd = p.currInd
p.currInd = p.tok.indent
body
@@ -202,7 +202,7 @@ proc isRightAssociative(tok: TToken): bool {.inline.} =
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token.
template considerStrongSpaces(x): expr =
template considerStrongSpaces(x): untyped =
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType
@@ -214,7 +214,7 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
if L > 1 and tok.ident.s[L-1] == '>' and
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
template considerAsgn(value: expr) =
template considerAsgn(value: untyped) =
result = if tok.ident.s[L-1] == '=': 1 else: value
case relevantChar
@@ -326,6 +326,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
getTok(p)
else:
parMessage(p, errIdentifierExpected, p.tok)
break
eat(p, tkAccent)
else:
if allowNil and p.tok.tokType == tkNil:
@@ -685,11 +686,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| | '{' optInd indexExprList optPar '}'
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
result = r
template somePar() =
if p.tok.strongSpaceA > 0:
if p.strongSpaces:
break
else:
parMessage(p, warnDeprecated,
"a [b] will be parsed as command syntax; spacing")
while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
case p.tok.tokType
of tkParLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
somePar()
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
@@ -704,10 +713,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = dotExpr(p, result)
result = parseGStrLit(p, result)
of tkBracketLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
somePar()
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
somePar()
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
if p.inPragma == 0:
@@ -963,8 +972,9 @@ proc parseDoBlock(p: var TParser): PNode =
proc parseDoBlocks(p: var TParser, call: PNode) =
#| doBlocks = doBlock ^* IND{=}
if p.tok.tokType == tkDo:
addSon(call, parseDoBlock(p))
while sameInd(p) and p.tok.tokType == tkDo:
#withInd(p):
# addSon(call, parseDoBlock(p))
while sameOrNoInd(p) and p.tok.tokType == tkDo:
addSon(call, parseDoBlock(p))
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =

View File

@@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
# system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing)
message(n.info, hintProcessing, $idgen.gBackendId)
message(n.info, hintProcessing, $idgen.gFrontendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)

View File

@@ -75,7 +75,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
result = matchNodeKinds(p.constraint, n)
if not result: return
if isNil(n.typ):
result = p.typ.kind in {tyEmpty, tyStmt}
result = p.typ.kind in {tyVoid, tyStmt}
else:
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
@@ -129,7 +129,7 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
result = bindOrCheck(c, p.sons[2].sym, arglist)
proc matches(c: PPatternContext, p, n: PNode): bool =
# hidden conversions (?)
let n = skipHidden(n)
if nfNoRewrite in n.flags:
result = false
elif isPatternParam(c, p):

View File

@@ -159,7 +159,7 @@ type
# alias conditionals to condsyms (end of module).
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64
type
TEndian* = enum
@@ -187,7 +187,8 @@ const
(name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)]
var
targetCPU*, hostCPU*: TSystemCPU

View File

@@ -63,11 +63,12 @@ const
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims}
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
wIntDefine, wStrDefine}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wLocks, wTags, wGcSafe}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation
@@ -89,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
else:
invalidPragma(it)
proc setExternName(s: PSym, extname: string) =
s.loc.r = rope(extname % s.name.s)
proc setExternName(s: PSym, extname: string, info: TLineInfo) =
# special cases to improve performance:
if extname == "$1":
s.loc.r = rope(s.name.s)
elif '$' notin extname:
s.loc.r = rope(extname)
else:
try:
s.loc.r = rope(extname % s.name.s)
except ValueError:
localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
if gCmd == cmdPretty and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
proc makeExternImport(s: PSym, extname: string) =
setExternName(s, extname)
proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname, info)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
proc validateExternCName(s: PSym, info: TLineInfo) =
## Validates that the symbol name in s.loc.r is a valid C identifier.
##
## 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 = $s.loc.r
if target.len < 1 or target[0] notin IdentStartChars or
not target.allCharsInSet(IdentChars):
localError(info, errGenerated, "invalid exported symbol")
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname)
# XXX to fix make it work with nimrtl.
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
# validateExternCName(s, info)
setExternName(s, extname, info)
incl(s.flags, sfExportc)
proc processImportCompilerProc(s: PSym, extname: string) =
setExternName(s, extname)
proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname, info)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
incl(s.loc.flags, lfImportCompilerProc)
proc processImportCpp(s: PSym, extname: string) =
setExternName(s, extname)
proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname, info)
incl(s.flags, sfImportc)
incl(s.flags, sfInfixCall)
excl(s.flags, sfForward)
@@ -133,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true
proc processImportObjC(s: PSym, extname: string) =
setExternName(s, extname)
proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname, info)
incl(s.flags, sfImportc)
incl(s.flags, sfNamedParamCall)
excl(s.flags, sfForward)
@@ -256,8 +252,9 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
if (sym == nil) or (sym.kind == skModule):
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
expectDynlibNode(c, n))
let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
if not lib.isOverriden:
POptionEntry(c.optionStack.tail).dynlib = lib
else:
if n.kind == nkExprColonExpr:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
@@ -276,6 +273,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
proc processNote(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
(n.sons[0].kind == nkBracketExpr) and
(n.sons[0].sons.len == 2) and
(n.sons[0].sons[1].kind == nkIdent) and
(n.sons[0].sons[0].kind == nkIdent):
#and (n.sons[1].kind == nkIdent):
@@ -391,21 +389,25 @@ type
TLinkFeature = enum
linkNormal, linkSys
proc processCompile(c: PContext, n: PNode) =
proc relativeFile(c: PContext; n: PNode; ext=""): string =
var s = expectStrLit(c, n)
var found = findFile(s)
if found == "": found = s
var trunc = changeFileExt(found, "")
if not isAbsolute(found):
found = parentDir(n.info.toFullPath) / found
if ext.len > 0 and splitFile(s).ext == "":
s = addFileExt(s, ext)
result = parentDir(n.info.toFullPath) / s
if not fileExists(result):
if isAbsolute(s): result = s
else:
result = findFile(s)
if result.len == 0: result = s
proc processCompile(c: PContext, n: PNode) =
let found = relativeFile(c, n)
let trunc = found.changeFileExt("")
extccomp.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false))
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
var f = expectStrLit(c, n)
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
var found = findFile(f)
if found == "": found = f # use the default
let found = relativeFile(c, n, CC[cCompiler].objExt)
case feature
of linkNormal: extccomp.addFileToLink(found)
of linkSys:
@@ -564,7 +566,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
localError(pragma.info, "list of key:value pairs expected"); return
for n in pragma:
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
let dest = qualifiedLookUp(c, n[1])
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
let src = considerQuotedIdent(n[0])
let alias = newSym(skAlias, src, dest, n[0].info)
incl(alias.flags, sfExported)
@@ -589,7 +591,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
# and perform the lookup on demand instead.
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
else:
result = qualifiedLookUp(c, n)
result = qualifiedLookUp(c, n, {checkUndeclared})
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool =
@@ -616,20 +618,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
of wExtern: setExternName(sym, expectStrLit(c, it))
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
of wImmediate:
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
if sym.kind in {skTemplate, skMacro}:
incl(sym.flags, sfImmediate)
incl(sym.flags, sfAllUntyped)
message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
else: invalidPragma(it)
of wDirty:
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it)
of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, "$1"))
processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
of wImportObjC:
processImportObjC(sym, getOptionalStr(c, it, "$1"))
processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
of wAlign:
if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it)
@@ -894,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wBase:
noVal(it)
sym.flags.incl sfBase
of wIntDefine:
sym.magic = mIntDefine
of wStrDefine:
sym.magic = mStrDefine
else: invalidPragma(it)
else: invalidPragma(it)

View File

@@ -704,7 +704,10 @@ proc gcase(g: var TSrcGen, n: PNode) =
proc gproc(g: var TSrcGen, n: PNode) =
var c: TContext
if n.sons[namePos].kind == nkSym:
put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
let s = n.sons[namePos].sym
put(g, tkSymbol, renderDefinitionName(s))
if sfGenSym in s.flags:
put(g, tkIntLit, $s.id)
else:
gsub(g, n.sons[namePos])
@@ -712,7 +715,11 @@ proc gproc(g: var TSrcGen, n: PNode) =
gpattern(g, n.sons[patternPos])
let oldCheckAnon = g.checkAnon
g.checkAnon = true
gsub(g, n.sons[genericParamsPos])
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
n[miscPos][1].kind != nkEmpty:
gsub(g, n[miscPos][1])
else:
gsub(g, n.sons[genericParamsPos])
g.checkAnon = oldCheckAnon
gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos])
@@ -794,7 +801,8 @@ proc gident(g: var TSrcGen, n: PNode) =
else:
t = tkOpr
put(g, t, s)
if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags):
put(g, tkIntLit, $n.sym.id)
proc doParamsAux(g: var TSrcGen, params: PNode) =
if params.len > 1:
@@ -802,7 +810,7 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
gsemicolon(g, params, 1)
put(g, tkParRi, ")")
if params.sons[0].kind != nkEmpty:
if params.len > 0 and params.sons[0].kind != nkEmpty:
putWithSpace(g, tkOpr, "->")
gsub(g, params.sons[0])

View File

@@ -21,7 +21,7 @@ proc toStrMaxPrecision*(f: BiggestFloat): string =
if f > 0.0: result = "INF"
else: result = "-INF"
else:
var buf: array [0..80, char]
var buf: array[0..80, char]
c_sprintf(buf, "%#.16e", f)
result = $buf
@@ -64,7 +64,7 @@ const
const
vintDelta = 5
template encodeIntImpl(self: expr) =
template encodeIntImpl(self) =
var d: char
var v = x
var rem = v mod 190

View File

@@ -13,10 +13,10 @@
import
ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times, osproc
os, times, osproc, wordrecg, strtabs
# we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle
from strutils import cmpIgnoreStyle, contains
proc listDirs(a: VmArgs, filter: set[PathComponent]) =
let dir = getString(a, 0)
@@ -116,12 +116,27 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
setResult(a, options.command)
cbconf switch:
processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
cbconf hintImpl:
processSpecificNote(a.getString 0, wHint, passPP, unknownLineInfo(),
a.getString 1)
cbconf warningImpl:
processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(),
a.getString 1)
cbconf patchFile:
let key = a.getString(0) & "_" & a.getString(1)
var val = a.getString(2).addFileExt(NimExt)
if {'$', '~'} in val:
val = pathSubs(val, vthisDir)
elif not isAbsolute(val):
val = vthisDir / val
gModuleOverrides[key] = val
cbconf selfExe:
setResult(a, os.getAppFilename())
proc runNimScript*(scriptName: string) =
proc runNimScript*(scriptName: string; freshDefines=true) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
if freshDefines: initDefines()
defineSymbol("nimscript")
defineSymbol("nimconfig")

View File

@@ -59,21 +59,11 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
# templates perform some quick check whether the cursor is actually in
# the generic or template.
when defined(nimsuggest):
assert gCmd == cmdIdeTools
if requiresCheck:
if gCmd == cmdIdeTools and requiresCheck:
#if optIdeDebug in gGlobalOptions:
# echo "passing to safeSemExpr: ", renderTree(n)
discard safeSemExpr(c, n)
proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
let named = typeToString(formal)
let desc = typeToString(formal, preferDesc)
let x = if named == desc: named else: named & " = " & desc
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
typeToString(actual) & ") " &
`%`(msgKindToString(errButExpectedX), [x]))
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
if arg.typ.isNil:
localError(arg.info, errExprXHasNoType,
@@ -174,7 +164,7 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLower
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
@@ -316,6 +306,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
include hlo, seminst, semcall
when false:
# hopefully not required:
proc resetSemFlag(n: PNode) =
excl n.flags, nfSem
for i in 0 ..< n.safeLen:
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode =
## Semantically check the output of a macro.
@@ -329,6 +326,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
c.friendModules.add(s.owner.getModule)
result = n
excl(n.flags, nfSem)
#resetSemFlag n
if s.typ.sons[0] == nil:
result = semStmt(c, result)
else:
@@ -363,7 +362,6 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags)
@@ -419,17 +417,42 @@ proc myOpen(module: PSym): PPassContext =
c.importTable.addSym(module) # a module knows itself
if sfSystemModule in module.flags:
magicsys.systemModule = module # set global variable!
else:
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
c.topLevelScope = openScope(c)
# don't be verbose unless the module belongs to the main package:
if module.owner.id == gMainPackageId:
gNotes = gMainPackageNotes
else:
if gMainPackageNotes == {}: gMainPackageNotes = gNotes
gNotes = ForeignPackageNotes
result = c
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module)
for m in items(rd.methods): methodDef(m, true)
proc isImportSystemStmt(n: PNode): bool =
if magicsys.systemModule == nil: return false
case n.kind
of nkImportStmt:
for x in n:
let f = checkModuleName(x)
if f == magicsys.systemModule.info.fileIndex:
return true
of nkImportExceptStmt, nkFromStmt:
let f = checkModuleName(n[0])
if f == magicsys.systemModule.info.fileIndex:
return true
else: discard
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
if c.topStmts == 0 and not isImportSystemStmt(n):
if sfSystemModule notin c.module.flags and
n.kind notin {nkEmpty, nkCommentStmt}:
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
inc c.topStmts
else:
inc c.topStmts
if sfNoForward in c.module.flags:
result = semAllTypeSections(c, n)
else:

View File

@@ -183,7 +183,7 @@ proc newSeqCall(c: PContext; x, y: PNode): PNode =
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
of tyNone, tyEmpty: discard
of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
tyPtr, tyString, tyRef:
defaultOp(c, t, body, x, y)

View File

@@ -53,7 +53,18 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
if symx.kind in filter:
syms.add((symx, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol)
if syms.len == 0: return
if syms.len == 0:
when false:
if skIterator notin filter:
# also try iterators, but these are 2nd class:
symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
if symx.kind == skIterator:
syms.add((symx, 100))
symx = nextOverloadIter(o, c, headSymbol)
if syms.len == 0: return
else:
return
var z: TCandidate
initCandidate(c, best, syms[0][0], initialBinding, symScope)
@@ -69,7 +80,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# gDebug = true
matches(c, n, orig, z)
if errors != nil:
errors.safeAdd(sym)
errors.safeAdd((sym, int z.mutabilityProblem))
if z.errors != nil:
for err in z.errors:
errors.add(err)
@@ -111,7 +122,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
let proto = describeArgs(c, n, 1, preferName)
var prefer = preferName
for err in errors:
for err, mut in items(errors):
var errProto = ""
let n = err.typ.n
for i in countup(1, n.len - 1):
@@ -123,14 +134,21 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
if errProto == proto:
prefer = preferModuleInfo
break
# now use the information stored in 'prefer' to produce a nice error message:
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1, prefer))
add(result, ')')
var candidates = ""
for err in errors:
add(candidates, err.getProcHeader(prefer))
for err, mut in items(errors):
if err.kind in routineKinds and err.ast != nil:
add(candidates, renderTree(err.ast,
{renderNoBody, renderNoComments,renderNoPragmas}))
else:
add(candidates, err.getProcHeader(prefer))
add(candidates, "\n")
if mut != 0 and mut < n.len:
add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n")
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
@@ -138,6 +156,20 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
else:
localError(n.info, errGenerated, result)
proc bracketNotFoundError(c: PContext; n: PNode) =
var errors: CandidateErrors = @[]
var o: TOverloadIter
let headSymbol = n[0]
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
if symx.kind in routineKinds:
errors.add((symx, 0))
symx = nextOverloadIter(o, c, headSymbol)
if errors.len == 0:
localError(n.info, "could not resolve: " & $n)
else:
notFoundError(c, n, errors)
proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds;
errors: var CandidateErrors): TCandidate =
@@ -154,8 +186,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
template pickBest(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors)
pickBest(f)
let overloadsState = result.state
@@ -226,7 +256,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
#notFoundError(c, n, errors)
return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
internalAssert result.state == csMatch
@@ -295,8 +324,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
var finalCallee = x.calleeSym
markUsed(n.sons[0].info, finalCallee)
styleCheckUse(n.sons[0].info, finalCallee)
if finalCallee.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
assert finalCallee.ast != nil
if x.hasFauxMatch:
result = x.call
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
@@ -315,12 +343,12 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
# are added as normal params.
for s in instantiateGenericParamList(c, gp, x.bindings):
case s.kind
of skConst:
x.call.add s.ast
of skType:
x.call.add newSymNode(s, n.info)
else:
internalAssert false
of skConst:
x.call.add s.ast
of skType:
x.call.add newSymNode(s, n.info)
else:
internalAssert false
result = x.call
instGenericConvertersSons(c, result, x)
@@ -361,7 +389,14 @@ proc explicitGenericInstError(n: PNode): PNode =
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var m: TCandidate
initCandidate(c, m, s, n)
# binding has to stay 'nil' for this to work!
initCandidate(c, m, s, nil)
for i in 1..sonsLen(n)-1:
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
let arg = n[i].typ
let tm = typeRel(m, formal, arg, true)
if tm in {isNone, isConvertible}: return nil
var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n.info, s)
styleCheckUse(n.info, s)
@@ -382,6 +417,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(n)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
@@ -394,11 +430,12 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# it suffices that the candidate has the proper number of generic
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate))
let x = explicitGenericSym(c, n, candidate)
if x != nil: result.add(x)
# get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0]
# candidateCount != 1: return explicitGenericInstError(n)
elif result.len == 0: result = explicitGenericInstError(n)
else:
result = explicitGenericInstError(n)

View File

@@ -47,7 +47,7 @@ type
efLValue, efWantIterator, efInTypeof,
efWantStmt, efAllowStmt, efDetermineType,
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
efNoProcvarCheck
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo
TExprFlags* = set[TExprFlag]
TTypeAttachedOp* = enum
@@ -99,11 +99,12 @@ type
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
# naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
topStmts*: int # counts the number of encountered top level statements
lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.nimcall.}
op: TTypeAttachedOp; col: int): PSym {.nimcall.}
selfName*: PIdent
signatures*: TStrTable

View File

@@ -87,7 +87,7 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
result = nil
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
template maybeAddLine(e: expr): stmt =
template maybeAddLine(e) =
let stmt = e
if stmt != nil:
if result == nil: result = newNode(nkStmtList)
@@ -139,6 +139,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
t = t.skipTypes({tyGenericInst})
case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
t.destructor = analyzingDestructor
if instantiateDestructor(c, t.sons[0]) != nil:
t.destructor = getCompilerProc"nimDestroyRange"
return t

View File

@@ -15,7 +15,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
markUsed(n.info, s)
styleCheckUse(n.info, s)
pushInfoContext(n.info)
result = evalTemplate(n, s, getCurrOwner())
result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
popInfoContext()
@@ -24,16 +24,15 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand})
if result.kind == nkEmpty and result.typ.isNil:
#if result.kind == nkEmpty and result.typ.isNil:
# do not produce another redundant error message:
#raiseRecoverableError("")
result = errorNode(c, n)
# result = errorNode(c, n)
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyVar: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyEmpty, c)
result.typ.flags.incl tfVoid
result.typ = newTypeS(tyVoid, c)
else:
localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
@@ -51,7 +50,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
else:
# XXX tyGenericInst here?
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result)
semDestructorCheck(c, result, flags)
@@ -74,8 +72,12 @@ proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast)
result.typ = s.typ
result.info = n.info
if result.isNil:
localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
result = newSymNode(s)
else:
result.typ = s.typ
result.info = n.info
type
TConvStatus = enum
@@ -83,8 +85,9 @@ type
convNotNeedeed,
convNotLegal
proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
return if inheritanceDiff(castDest, src) == high(int):
proc checkConversionBetweenObjects(castDest, src: PType; pointers: int): TConvStatus =
let diff = inheritanceDiff(castDest, src)
return if diff == high(int) or (pointers > 1 and diff != 0):
convNotLegal
else:
convOK
@@ -101,13 +104,15 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
return
var d = skipTypes(castDest, abstractVar)
var s = skipTypes(src, abstractVar-{tyTypeDesc})
var pointers = 0
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
d = d.lastSon
s = s.lastSon
inc pointers
if d == nil:
result = convNotLegal
elif d.kind == tyObject and s.kind == tyObject:
result = checkConversionBetweenObjects(d, s)
result = checkConversionBetweenObjects(d, s, pointers)
elif (skipTypes(castDest, abstractVarRange).kind in IntegralTypes) and
(skipTypes(src, abstractVarRange-{tyTypeDesc}).kind in IntegralTypes):
# accept conversion between integral types
@@ -186,17 +191,17 @@ proc semConv(c: PContext, n: PNode): PNode =
case status
of convOK:
# handle SomeProcType(SomeGenericProc)
# XXX: This needs fixing. checkConvertible uses typeRel internally, but
# doesn't bother to perform the work done in paramTypeMatchAux/fitNode
# so we are redoing the typeRel work here. Why does semConv exist as a
# separate proc from fitNode?
if op.kind == nkSym and op.sym.isGenericRoutine:
result.sons[1] = fitNode(c, result.typ, result.sons[1])
elif op.kind == nkPar and targetType.kind == tyTuple:
op = fitNode(c, targetType, op)
of convNotNeedeed:
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
of convNotLegal:
localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
[op.typ.typeToString, result.typ.typeToString])
result = fitNode(c, result.typ, result.sons[1])
if result == nil:
localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
[op.typ.typeToString, result.typ.typeToString])
else:
for i in countup(0, sonsLen(op) - 1):
let it = op.sons[i]
@@ -206,7 +211,7 @@ proc semConv(c: PContext, n: PNode): PNode =
styleCheckUse(n.info, it.sym)
markIndirect(c, it.sym)
return it
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
errorUseQualifier(c, n.info, op.sons[0].sym)
proc semCast(c: PContext, n: PNode): PNode =
## Semantically analyze a casting ("cast[type](param)")
@@ -594,6 +599,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
result = n
if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
var callee = n.sons[0].sym
# workaround for bug #537 (overly aggressive inlining leading to
# wrong NimNode semantics):
if n.typ != nil and tfTriggersCompileTime in n.typ.flags: return
# constant folding that is necessary for correctness of semantic pass:
if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
@@ -710,25 +718,60 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
initCandidate(c, result, t)
matches(c, n, nOrig, result)
proc bracketedMacro(n: PNode): PSym =
if n.len >= 1 and n[0].kind == nkSym:
result = n[0].sym
if result.kind notin {skMacro, skTemplate}:
result = nil
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
flags: TExprFlags): PNode =
# We received untransformed bracket expression coming from macroOrTmpl[].
# Transform it to macro or template call, where first come normal
# arguments, next come generic template arguments.
var sons = newSeq[PNode]()
sons.add inner.sons[0]
# Normal arguments:
for i in 1..<outer.len:
sons.add outer.sons[i]
# Generic template arguments from bracket expression:
for i in 1..<inner.len:
sons.add inner.sons[i]
shallowCopy(outer.sons, sons)
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
# However passing to semDirectOp doesn't work here.
case s.kind
of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
of skTemplate: result = semTemplateExpr(c, outer, s, flags)
else: assert(false)
return
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
checkMinSonsLen(n, 1)
var prc = n.sons[0]
if n.sons[0].kind == nkDotExpr:
checkSonsLen(n.sons[0], 2)
n.sons[0] = semFieldAccess(c, n.sons[0])
if n.sons[0].kind == nkDotCall:
let n0 = semFieldAccess(c, n.sons[0])
if n0.kind == nkDotCall:
# it is a static call!
result = n.sons[0]
result = n0
result.kind = nkCall
result.flags.incl nfExplicitCall
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
return semExpr(c, result, flags)
else:
n.sons[0] = n0
else:
n.sons[0] = semExpr(c, n.sons[0])
n.sons[0] = semExpr(c, n.sons[0], {efInCall})
let t = n.sons[0].typ
if t != nil and t.kind == tyVar:
n.sons[0] = newDeref(n.sons[0])
elif n.sons[0].kind == nkBracketExpr:
let s = bracketedMacro(n.sons[0])
if s != nil:
return semBracketedMacro(c, n, n.sons[0], s, flags)
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
@@ -958,8 +1001,20 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
of skMacro:
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
else:
result = semMacroExpr(c, n, n, s, flags)
of skTemplate:
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
else:
result = semTemplateExpr(c, n, s, flags)
of skParam:
markUsed(n.info, s)
styleCheckUse(n.info, s)
@@ -1011,8 +1066,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
of skField:
if c.p != nil and c.p.selfSym != nil:
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
var p = c.p
while p != nil and p.selfSym == nil:
p = p.next
if p != nil and p.selfSym != nil:
var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
var check: PNode = nil
if ty.kind == tyObject:
@@ -1025,7 +1083,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
markUsed(n.info, f)
styleCheckUse(n.info, f)
result = newNodeIT(nkDotExpr, n.info, f.typ)
result.add makeDeref(newSymNode(c.p.selfSym))
result.add makeDeref(newSymNode(p.selfSym))
result.add newSymNode(f) # we now have the correct field
if check != nil:
check.sons[0] = result
@@ -1051,7 +1109,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# here at all!
#if isSymChoice(n.sons[1]): return
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
if s != nil:
if s.kind in OverloadableSyms:
result = symChoice(c, n, s, scClosed)
@@ -1186,7 +1244,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0])
return
checkMinSonsLen(n, 2)
n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck})
# make sure we don't evaluate generic macros/templates
n.sons[0] = semExprWithType(c, n.sons[0],
{efNoProcvarCheck, efNoEvaluateGeneric})
let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
case arr.kind
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
@@ -1229,12 +1289,30 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
let s = if n.sons[0].kind == nkSym: n.sons[0].sym
elif n[0].kind in nkSymChoices: n.sons[0][0].sym
else: nil
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
# type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s)
elif s != nil and s.kind == skType:
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
if s != nil:
case s.kind
of skProc, skMethod, skConverter, skIterator:
# type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s)
of skMacro, skTemplate:
if efInCall in flags:
# We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
# Return as is, so it can be transformed into complete macro or
# template call in semIndirectOp caller.
result = n
else:
# We are processing macroOrTmpl[] not in call. Transform it to the
# macro or template call with generic arguments here.
n.kind = nkCall
case s.kind
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
else: discard
of skType:
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
else:
c.p.bracketExpr = n.sons[0]
else:
c.p.bracketExpr = n.sons[0]
@@ -1287,7 +1365,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
n.sons[1] = takeImplicitAddr(c, ri)
x.typ.flags.incl tfVarIsPtr
template resultTypeIsInferrable(typ: PType): expr =
template resultTypeIsInferrable(typ: PType): untyped =
typ.isMetaType and typ.kind != tyTypeDesc
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
@@ -1313,15 +1391,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# --> `[]=`(a, i, x)
let oldBracketExpr = c.p.bracketExpr
a = semSubscript(c, a, {efLValue})
if a == nil and mode != noOverloadedSubscript:
if a == nil:
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
add(result, n[1])
result = semExprNoType(c, result)
c.p.bracketExpr = oldBracketExpr
return result
elif a == nil:
localError(n.info, "could not resolve: " & $n[0])
return n
if mode == noOverloadedSubscript:
bracketNotFoundError(c, result)
return n
else:
result = semExprNoType(c, result)
c.p.bracketExpr = oldBracketExpr
return result
c.p.bracketExpr = oldBracketExpr
of nkCurlyExpr:
# a{i} = x --> `{}=`(a, i, x)
@@ -1557,8 +1636,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
result.flags = {sfGenSym}
proc semExpandToAst(c: PContext, n: PNode): PNode =
var macroCall = n[1]
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
let macroCall = n[1]
let expandedSym = expectMacroOrTemplateCall(c, macroCall)
if expandedSym.kind == skError: return n
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
@@ -1566,11 +1645,12 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
styleCheckUse(n.info, expandedSym)
for i in countup(1, macroCall.len-1):
#if macroCall.sons[0].typ.sons[i].kind != tyExpr:
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
# Preserve the magic symbol in order to be handled in evals.nim
internalAssert n.sons[0].sym.magic == mExpandToAst
#n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
else: sysTypeFromName"PNimrodNode"
result = n
@@ -1810,8 +1890,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# the correct branch. Otherwise the AST will be passed through semStmt.
result = nil
template setResult(e: expr) =
if semCheck: result = semStmt(c, e) # do not open a new scope!
template setResult(e: untyped) =
if semCheck: result = semExpr(c, e) # do not open a new scope!
else: result = e
# Check if the node is "when nimvm"
@@ -1820,6 +1900,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# else:
# ...
var whenNimvm = false
var typ = commonTypeBegin
if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
n.sons[1].kind == nkElse:
let exprNode = n.sons[0].sons[0]
@@ -1836,7 +1917,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2)
if whenNimvm:
if semCheck:
it.sons[1] = semStmt(c, it.sons[1])
it.sons[1] = semExpr(c, it.sons[1])
typ = commonType(typ, it.sons[1].typ)
result = n # when nimvm is not elimited until codegen
else:
var e = semConstExpr(c, it.sons[0])
@@ -1850,12 +1932,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 1)
if result == nil or whenNimvm:
if semCheck:
it.sons[0] = semStmt(c, it.sons[0])
it.sons[0] = semExpr(c, it.sons[0])
typ = commonType(typ, it.sons[0].typ)
if result == nil:
result = it.sons[0]
else: illFormedAst(n)
if result == nil:
result = newNodeI(nkEmpty, n.info)
if whenNimvm: result.typ = typ
# The ``when`` statement implements the mechanism for platform dependent
# code. Thus we try to ensure here consistent ID allocation after the
# ``when`` statement.
@@ -2132,7 +2216,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
var s = lookUp(c, n)
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
else: {checkUndeclared, checkModule, checkAmbiguity}
var s = qualifiedLookUp(c, n, checks)
if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skConverter, skIterator}:
@@ -2220,7 +2306,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
elif n.len == 1:
result = semObjConstr(c, n, flags)
elif contains(c.ambiguousSymbols, s.id):
localError(n.info, errUseQualifier, s.name.s)
errorUseQualifier(c, n.info, s)
elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
of skProc, skMethod, skConverter, skIterator:
@@ -2336,7 +2422,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
result = evalFrom(c, n)
of nkIncludeStmt:
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
#if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
result = evalInclude(c, n)
of nkExportStmt, nkExportExceptStmt:
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")

View File

@@ -143,7 +143,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
const ordIntLit = {nkIntLit..nkUInt64Lit}
result = n.typ
template commutativeOp(opr: expr) {.immediate.} =
template commutativeOp(opr: untyped) =
let a = n.sons[1]
let b = n.sons[2]
if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ):
@@ -151,7 +151,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
opr(pickMinInt(a), pickMinInt(b)),
opr(pickMaxInt(a), pickMaxInt(b)))
template binaryOp(opr: expr) {.immediate.} =
template binaryOp(opr: untyped) =
let a = n.sons[1]
let b = n.sons[2]
if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}:
@@ -286,13 +286,14 @@ 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: result = newIntNodeT(not getInt(a), n)
of mLengthStr, mXLenStr:
if a.kind == nkNilLit: result = newIntNodeT(0, n)
else: result = newIntNodeT(len(getStr(a)), n)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
of mLengthSeq, mLengthOpenArray, mXLenSeq:
if a.kind == nkNilLit: result = newIntNodeT(0, n)
else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit:
result = newIntNodeT(0, n)
elif a.kind in {nkStrLit..nkTripleStrLit}:
result = newIntNodeT(len a.strVal, n)
else:
result = newIntNodeT(sonsLen(a), n) # BUGFIX
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n)
@@ -419,7 +420,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
int(getOrdValue(c))), n)
of mFloatToStr: result = newStrNodeT($getFloat(a), n)
of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
of mCStrToStr, mCharToStr:
if a.kind == nkBracket:
var s = ""
for b in a.sons:
s.add b.getStrOrChar
result = newStrNodeT(s, n)
else:
result = newStrNodeT(getStrOrChar(a), n)
of mStrToStr: result = a
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
of mArrToSeq:
@@ -482,7 +490,7 @@ proc leValueConv(a, b: PNode): bool =
of nkCharLit..nkUInt64Lit:
case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
else: internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit:
case b.kind
@@ -627,14 +635,20 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
of mAppType: result = getAppType(n)
of mNaN: result = newFloatNodeT(NaN, n)
of mInf: result = newFloatNodeT(Inf, n)
of mNegInf: result = newFloatNodeT(NegInf, n)
of mIntDefine:
if isDefined(s.name):
result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
of mStrDefine:
if isDefined(s.name):
result = newStrNodeT(lookupSymbol(s.name), n)
else:
if sfFakeConst notin s.flags: result = copyTree(s.ast)
result = copyTree(s.ast)
of {skProc, skMethod}:
result = n
of skType:

View File

@@ -47,8 +47,11 @@ proc semGenericStmtScope(c: PContext, n: PNode,
result = semGenericStmt(c, n, flags, ctx)
closeScope(c)
template macroToExpand(s: expr): expr =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
template macroToExpand(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
template macroToExpandSym(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx): PNode =
@@ -61,14 +64,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
of skProc, skMethod, skIterator, skConverter, skModule:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
if macroToExpandSym(s):
styleCheckUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpand(s):
if macroToExpandSym(s):
styleCheckUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
@@ -124,7 +127,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
assert n.kind == nkDotExpr
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
var s = qualifiedLookUp(c, n, luf)
if s != nil:
@@ -199,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode,
if s != nil:
incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
let sc = symChoice(c, fn, s,
if s.name.id in ctx.toMixin: scForceOpen else: scOpen)
case s.kind
of skMacro:
if macroToExpand(s):
if macroToExpand(s) and sc.safeLen <= 1:
styleCheckUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
result = semGenericStmt(c, result, flags, ctx)
else:
n.sons[0] = symChoice(c, fn, s, scOption)
n.sons[0] = sc
result = n
mixinContext = true
of skTemplate:
if macroToExpand(s):
if macroToExpand(s) and sc.safeLen <= 1:
styleCheckUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
result = semGenericStmt(c, result, flags, ctx)
else:
n.sons[0] = symChoice(c, fn, s, scOption)
n.sons[0] = sc
result = n
# BUGFIX: we must not return here, we need to do first phase of
# symbol lookup. Also since templates and macros can do scope injections
@@ -227,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# Leave it as an identifier.
discard
of skProc, skMethod, skIterator, skConverter, skModule:
result.sons[0] = symChoice(c, fn, s, scOption)
result.sons[0] = sc
# do not check of 's.magic==mRoof' here because it might be some
# other '^' but after overload resolution the proper one:
if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
@@ -426,7 +430,12 @@ proc semGenericStmt(c: PContext, n: PNode,
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
var body: PNode
if n.sons[namePos].kind == nkSym: body = n.sons[namePos].sym.getBody
if n.sons[namePos].kind == nkSym:
let s = n.sons[namePos].sym
if sfGenSym in s.flags and s.ast == nil:
body = n.sons[bodyPos]
else:
body = s.getBody
else: body = n.sons[bodyPos]
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
closeScope(c)

View File

@@ -43,9 +43,11 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
if arg.name.id == c.selfName.id:
c.p.selfSym = arg
arg.flags.incl sfIsSelf
let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
if t.kind == tyObject:
var t = c.p.selfSym.typ.skipTypes(abstractPtrs)
while t.kind == tyObject:
addObjFieldsToLocalScope(c, t.n)
if t.sons[0] == nil: break
t = t.sons[0].skipTypes(abstractPtrs)
proc pushProcCon*(c: PContext; owner: PSym) =
rawPushProcCon(c, owner)
@@ -111,9 +113,9 @@ proc removeDefaultParamValues(n: PNode) =
# not possible... XXX We don't solve this issue here.
a.sons[L-1] = ast.emptyNode
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags:
if n.kind == nkSym and sfGenSym in n.sym.flags and n.sym.owner == orig:
let s = n.sym
var x = PSym(idTableGet(symMap, s))
if x == nil:
@@ -122,7 +124,7 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
idTablePut(symMap, s, x)
n.sym = x
else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
@@ -137,7 +139,7 @@ proc addProcDecls(c: PContext, fn: PSym) =
maybeAddResult(c, fn, fn.ast)
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if n.sons[bodyPos].kind != nkEmpty:
inc c.inGenericInst
# add it here, so that recursive generic procs are possible:
@@ -149,7 +151,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
let param = params[i].sym
if sfGenSym in param.flags:
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(b, result, symMap)
freshGenSyms(b, result, orig, symMap)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result)
@@ -165,7 +167,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
openScope(c)
var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody)
instantiateBody(c, n, nil, oldPrc)
instantiateBody(c, n, nil, oldPrc, s)
closeScope(c)
popInfoContext()
@@ -203,7 +205,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# The solution would be to move this logic into semtypinst, but
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc.
addDecl(c, prc)
#addDecl(c, prc)
pushInfoContext(info)
var cl = initTypeVars(c, pt, info, nil)
@@ -312,7 +314,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
if isNil(n.sons[bodyPos]):
n.sons[bodyPos] = copyTree(fn.getBody)
instantiateBody(c, n, fn.typ.n, result)
instantiateBody(c, n, fn.typ.n, result, fn)
sideEffectsCheck(c, result)
paramsTypeCheck(c, result.typ)
else:

View File

@@ -12,25 +12,26 @@
import ast, astalgo, msgs, types
proc ithField(n: PNode, field: int): PSym =
proc ithField(n: PNode, field: var int): PSym =
result = nil
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
result = ithField(n.sons[i], field-i)
result = ithField(n.sons[i], field)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
result = ithField(n.sons[0], field-1)
result = ithField(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field-1)
result = ithField(lastSon(n.sons[i]), field)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
of nkSym:
if field == 0: result = n.sym
else: dec(field)
else: discard
proc annotateType*(n: PNode, t: PType) =
@@ -39,10 +40,13 @@ proc annotateType*(n: PNode, t: PType) =
# to not to skip tyGenericInst
case n.kind
of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t
for i in 1 .. <n.len:
let field = x.n.ithField(i - 1)
if field.isNil: globalError n.info, "invalid field at index " & $i
var j = i-1
let field = x.n.ithField(j)
if field.isNil:
globalError n.info, "invalid field at index " & $i
else:
internalAssert(n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ)

View File

@@ -42,7 +42,10 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
result = semSubscript(c, result, flags)
c.p.bracketExpr = oldBracketExpr
if result.isNil:
localError(n.info, "could not resolve: " & $n)
let x = copyTree(n)
x.sons[0] = newIdentNode(getIdent"[]", n.info)
bracketNotFoundError(c, x)
#localError(n.info, "could not resolve: " & $n)
result = n
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
@@ -111,8 +114,12 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
proc semOrd(c: PContext, n: PNode): PNode =
result = n
result.typ = makeRangeType(c, firstOrd(n.sons[1].typ),
lastOrd(n.sons[1].typ), n.info)
let parType = n.sons[1].typ
if isOrdinalType(parType) or parType.kind == tySet:
result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info)
else:
localError(n.info, errOrdinalTypeExpected)
result.typ = errorType(c)
proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n)
@@ -130,7 +137,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = qualifiedLookUp(c, id)
let s = qualifiedLookUp(c, id, {checkUndeclared})
if s != nil:
# we need to mark all symbols:
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
@@ -203,7 +210,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n.sons[1]
else:
result = newNodeIT(nkCall, n.info, getSysType(tyInt))
result.add newSymNode(getSysMagic("-", mSubI), n.info)
let subi = getSysMagic("-", mSubI)
#echo "got ", typeToString(subi.typ)
result.add newSymNode(subi, n.info)
result.add lenExprB
result.add n.sons[1]
of mPlugin:

View File

@@ -74,8 +74,6 @@ type
currentSpawnId: int
inLoop: int
let opSlice = createMagic("slice", mSlice)
proc initAnalysisCtx(): AnalysisCtx =
result.locals = @[]
result.slices = @[]
@@ -123,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
else:
for i in 0 .. <n.safeLen: checkLocal(c, n.sons[i])
template `?`(x): expr = x.renderTree
template `?`(x): untyped = x.renderTree
proc checkLe(c: AnalysisCtx; a, b: PNode) =
case proveLe(c.guards, a, b)
@@ -262,7 +260,7 @@ proc min(a, b: PNode): PNode =
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
template pushSpawnId(c, body) {.dirty.} =
inc c.spawns
let oldSpawnId = c.currentSpawnId
c.currentSpawnId = c.spawns
@@ -399,7 +397,9 @@ proc transformSlices(n: PNode): PNode =
let op = n[0].sym
if op.name.s == "[]" and op.fromSystem:
result = copyNode(n)
result.add opSlice.newSymNode
let opSlice = newSymNode(createMagic("slice", mSlice))
opSlice.typ = getSysType(tyInt)
result.add opSlice
result.add n[1]
let slice = n[2].skipStmtList
result.add slice[1]

View File

@@ -151,7 +151,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
guardGlobal(a, n, g)
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
template compileToCpp(a): expr =
template compileToCpp(a): untyped =
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
if a.inTryStmt > 0 and not compileToCpp(a):
incl(s.flags, sfVolatile)
@@ -459,7 +459,7 @@ proc documentRaises*(n: PNode) =
if p4 != nil: n.sons[pragmasPos].add p4
if p5 != nil: n.sons[pragmasPos].add p5
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
proc importedFromC(n: PNode): bool =
# when imported from C, we assume GC-safety.
@@ -505,7 +505,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
# addr(x[]) can't be proven, but addr(x) can:
if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
elif (n.kind == nkSym and n.sym.kind in routineKinds) or
n.kind in procDefs+{nkObjConstr}:
n.kind in procDefs+{nkObjConstr, nkBracket}:
# 'p' is not nil obviously:
return
case impliesNotNil(tracked.guards, n)
@@ -532,7 +532,7 @@ proc isOwnedProcVar(n: PNode; owner: PSym): bool =
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
let a = skipConvAndClosure(n)
let op = a.typ
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
internalAssert op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
let s = n.skipConv

View File

@@ -17,7 +17,8 @@ proc semDiscard(c: PContext, n: PNode): PNode =
checkSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0])
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone:
localError(n.info, errInvalidDiscard)
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
result = n
@@ -137,7 +138,7 @@ proc fixNilType(n: PNode) =
proc discardCheck(c: PContext, result: PNode) =
if c.inTypeClass > 0: return
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
if result.kind == nkNilLit:
result.typ = nil
message(result.info, warnNilStatement)
@@ -303,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode =
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ, check=true)
result = result.sons[1]
let r1 = result.sons[1]
if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
result.info = n.info
result.typ = typ
else:
changeType(r1, typ, check=true)
result = r1
elif not sameType(result.typ, typ):
changeType(result, typ, check=false)
@@ -336,7 +343,7 @@ proc checkNilable(v: PSym) =
{tfNotNil, tfNeedsInit} * v.typ.flags != {}:
if v.ast.isNil:
message(v.info, warnProveInit, v.name.s)
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
elif tfNeedsInit in v.typ.flags and tfNotNil notin v.ast.typ.flags:
message(v.info, warnProveInit, v.name.s)
include semasgn
@@ -410,6 +417,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
if a.sons[length-1].kind != nkEmpty:
localError(a.info, "'using' sections cannot contain assignments")
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
@@ -444,10 +458,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
#changeType(def.skipConv, typ, check=true)
else:
typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and
typ.lastSon.kind == tyEmpty:
if hasEmpty(typ):
localError(def.info, errCannotInferTypeOfTheLiteral,
($typ.kind).substr(2).toLower)
($typ.kind).substr(2).toLowerAscii)
else:
def = ast.emptyNode
if symkind == skLet: localError(a.info, errLetNeedsInit)
@@ -535,7 +548,7 @@ proc semConst(c: PContext, n: PNode): PNode =
localError(a.sons[2].info, errConstExprExpected)
continue
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
localError(a.info, errXisNoType, typeToString(typ))
localError(a.info, "invalid type for const: " & typeToString(typ))
continue
v.typ = typ
v.ast = def # no need to copy
@@ -668,7 +681,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
let name = a.sons[0]
var s: PSym
if name.kind == nkDotExpr:
s = qualifiedLookUp(c, name)
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
localError(name.info, "only .partial objects can be extended")
else:
@@ -710,7 +723,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
a.sons[1] = s.typ.n
s.typ.size = -1 # could not be computed properly
# we fill it out later. For magic generics like 'seq', it won't be filled
# so we use tyEmpty instead of nil to not crash for strange conversions
# so we use tyNone instead of nil to not crash for strange conversions
# like: mydata.seq
rawAddSon(s.typ, newTypeS(tyNone, c))
s.ast = a
@@ -778,11 +791,16 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
var s = a.sons[0].sym
# compute the type's size and check for illegal recursions:
if a.sons[1].kind == nkEmpty:
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
var x = a[2]
while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
x = x.lastSon
if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
s.typ.kind notin {tyObject, tyEnum}:
# type aliases are hard:
#MessageOut('for type ' + typeToString(s.typ));
var t = semTypeNode(c, a.sons[2], nil)
if t.kind in {tyObject, tyEnum}:
var t = semTypeNode(c, x, nil)
assert t != nil
if t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
@@ -924,6 +942,17 @@ proc semProcAnnotation(c: PContext, prc: PNode;
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
return
proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
let orig = n.sons[genericParamsPos]
# we keep the original params around for better error messages, see
# issue https://github.com/nim-lang/Nim/issues/1713
result = semGenericParamList(c, orig)
if n.sons[miscPos].kind == nkEmpty:
n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig)
else:
n.sons[miscPos].sons[1] = orig
n.sons[genericParamsPos] = result
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda
@@ -942,8 +971,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
openScope(c)
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
gp = n.sons[genericParamsPos]
gp = setGenericParamsMisc(c, n)
else:
gp = newNodeI(nkGenericParams, n.info)
@@ -1165,8 +1193,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
openScope(c)
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
gp = n.sons[genericParamsPos]
gp = setGenericParamsMisc(c, n)
else:
gp = newNodeI(nkGenericParams, n.info)
# process parameters:
@@ -1231,6 +1258,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pushOwner(s)
s.options = gOptions
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if s.name.s[0] in {'.', '('}:
if s.name.s in [".", ".()", ".=", "()"] and not experimentalMode(c):
message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s)
if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags:
@@ -1245,7 +1275,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
c.p.wasForwarded = proto != nil
maybeAddResult(c, s, n)
if sfImportc notin s.flags:
if lfDynamicLib notin s.loc.flags:
# no semantic checking for importc:
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
# unfortunately we cannot skip this step when in 'system.compiles'
@@ -1285,6 +1315,7 @@ proc determineType(c: PContext, s: PSym) =
proc semIterator(c: PContext, n: PNode): PNode =
# gensym'ed iterator?
let isAnon = n[namePos].kind == nkEmpty
if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner()
@@ -1294,6 +1325,8 @@ proc semIterator(c: PContext, n: PNode): PNode =
var t = s.typ
if t.sons[0] == nil and s.typ.callConv != ccClosure:
localError(n.info, errXNeedsReturnType, "iterator")
if isAnon and s.typ.callConv == ccInline:
localError(n.info, "inline iterators are not first-class / cannot be assigned to variables")
# iterators are either 'inline' or 'closure'; for backwards compatibility,
# we require first class iterators to be marked with 'closure' explicitly
# -- at least for 0.9.2.
@@ -1325,9 +1358,24 @@ proc finishMethod(c: PContext, s: PSym) =
proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas)
# macros can transform methods to nothing:
if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym
if not isGenericRoutine(s):
if isGenericRoutine(s):
let tt = s.typ
var foundObj = false
# we start at 1 for now so that tparsecombnum continues to compile.
# XXX Revisit this problem later.
for col in countup(1, sonsLen(tt)-1):
let t = tt.sons[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody})
if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len:
foundObj = true
x.methods.safeAdd((col,s))
if not foundObj:
message(n.info, warnDeprecated, "generic method not attachable to object type")
else:
# why check for the body? bug #2400 has none. Checking for sfForward makes
# no sense either.
# and result.sons[bodyPos].kind != nkEmpty:
@@ -1340,6 +1388,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
checkSonsLen(n, bodyPos + 1)
result = semProcAux(c, n, skConverter, converterPragmas)
# macros can transform converters to nothing:
if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
@@ -1349,6 +1399,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1)
result = semProcAux(c, n, skMacro, macroPragmas)
# macros can transform macros to nothing:
if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")

View File

@@ -51,9 +51,10 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
var i = 0
a = initOverloadIter(o, c, n)
while a != nil:
if a.kind != skModule:
inc(i)
if i > 1: break
a = nextOverloadIter(o, c, n)
inc(i)
if i > 1: break
if i <= 1 and r != scForceOpen:
# XXX this makes more sense but breaks bootstrapping for now:
# (s.kind notin routineKinds or s.magic != mNone):
@@ -68,8 +69,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
incl(a.flags, sfUsed)
addSon(result, newSymNode(a, n.info))
if a.kind != skModule:
incl(a.flags, sfUsed)
addSon(result, newSymNode(a, n.info))
a = nextOverloadIter(o, c, n)
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
@@ -80,7 +82,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
# the same symbol!
# This is however not true anymore for hygienic templates as semantic
# processing for them changes the symbol table...
let s = qualifiedLookUp(c, a)
let s = qualifiedLookUp(c, a, {checkUndeclared})
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, n, s, scClosed)
@@ -577,13 +579,16 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else:
gp = newNodeI(nkGenericParams, n.info)
# process parameters:
var allUntyped = true
if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[paramsPos], gp, s)
# a template's parameters are not gensym'ed even if that was originally the
# case as we determine whether it's a template parameter in the template
# body by the absence of the sfGenSym flag:
for i in 1 .. s.typ.n.len-1:
s.typ.n.sons[i].sym.flags.excl sfGenSym
let param = s.typ.n.sons[i].sym
param.flags.excl sfGenSym
if param.typ.kind != tyExpr: allUntyped = false
if sonsLen(gp) > 0:
if n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
@@ -599,6 +604,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s.typ.n = newNodeI(nkFormalParams, n.info)
rawAddSon(s.typ, newTypeS(tyStmt, c))
addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
if allUntyped: incl(s.flags, sfAllUntyped)
if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
var ctx: TemplCtx
@@ -628,8 +634,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
c.patterns.add(s)
proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
template templToExpand(s: expr): expr =
s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags)
template templToExpand(s: untyped): untyped =
s.kind == skTemplate and (s.typ.len == 1 or sfAllUntyped in s.flags)
proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
# the param added in the current scope is actually wrong here for

View File

@@ -130,7 +130,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
if n.len < 1:
result = newConstraint(c, kind)
else:
let isCall = ord(n.kind in nkCallKinds)
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1)
var base = semTypeNode(c, n.lastSon, nil)
@@ -370,7 +370,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
result.n = newNodeI(nkRecList, n.info)
var check = initIntSet()
var counter = 0
for i in countup(0, sonsLen(n) - 1):
for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
@@ -393,20 +393,24 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
if result.n.len == 0: result.n = nil
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
# identifier with visibility
if n.kind == nkPostfix:
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
if sonsLen(n) == 2:
# for gensym'ed identifiers the identifier may already have been
# transformed to a symbol and we need to use that here:
result = newSymG(kind, n.sons[1], c)
var v = n.sons[0].ident
var v = considerQuotedIdent(n.sons[0])
if sfExported in allowed and v.id == ord(wStar):
incl(result.flags, sfExported)
else:
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
if not (sfExported in allowed):
localError(n.sons[0].info, errXOnlyAtModuleScope, "export")
else:
localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0]))
else:
illFormedAst(n)
else:
@@ -751,18 +755,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
addDecl(c, s)
# XXX: There are codegen errors if this is turned into a nested proc
template liftingWalk(typ: PType, anonFlag = false): expr =
template liftingWalk(typ: PType, anonFlag = false): untyped =
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
#proc liftingWalk(paramType: PType, anon = false): PType =
var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
else: nil
template maybeLift(typ: PType): expr =
template maybeLift(typ: PType): untyped =
let lifted = liftingWalk(typ)
(if lifted != nil: lifted else: typ)
template addImplicitGeneric(e: expr): expr =
template addImplicitGeneric(e): untyped =
addImplicitGenericImpl(e, paramTypId)
case paramType.kind:
@@ -942,7 +946,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if isType: localError(a.info, "':' expected")
if kind in {skTemplate, skMacro}:
typ = newTypeS(tyExpr, c)
elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
elif skipTypes(typ, {tyGenericInst}).kind == tyVoid:
continue
for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c)
@@ -974,7 +978,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if r != nil:
# turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil':
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
if skipTypes(r, {tyGenericInst}).kind != tyVoid:
# 'auto' as a return type does not imply a generic:
if r.kind == tyAnything:
# 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
@@ -1035,7 +1039,7 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil:
localError(n.info, "cannot instantiate the '$1' $2" %
[s.name.s, ($s.kind).substr(2).toLower])
[s.name.s, ($s.kind).substr(2).toLowerAscii])
return newOrPrevType(tyError, prev, c)
var t = s.typ
@@ -1094,10 +1098,14 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)
proc semTypeExpr(c: PContext, n: PNode): PType =
proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
var n = semExprWithType(c, n, {efDetermineType})
if n.typ.kind == tyTypeDesc:
result = n.typ.base
# fix types constructed by macros:
if prev != nil and prev.sym != nil and result.sym.isNil:
result.sym = prev.sym
result.sym.typ = result
else:
localError(n.info, errTypeExpected, n.renderTree)
result = errorType(c)
@@ -1177,7 +1185,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else:
localError(n.info, errGenerated, "invalid type")
elif n[0].kind notin nkIdentKinds:
result = semTypeExpr(c, n)
result = semTypeExpr(c, n, prev)
else:
let op = considerQuotedIdent(n.sons[0])
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
@@ -1218,7 +1226,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
result = typExpr.typ
else:
result = semTypeExpr(c, n)
result = semTypeExpr(c, n, prev)
of nkWhenStmt:
var whenResult = semWhen(c, n, false)
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
@@ -1241,6 +1249,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = copyType(result, getCurrOwner(), false)
for i in countup(1, n.len - 1):
result.rawAddSon(semTypeNode(c, n.sons[i], nil))
of mDistinct:
result = newOrPrevType(tyDistinct, prev, c)
addSonSkipIntLit(result, semTypeNode(c, n[1], nil))
of mVar:
result = newOrPrevType(tyVar, prev, c)
var base = semTypeNode(c, n.sons[1], nil)
if base.kind == tyVar:
localError(n.info, errVarVarTypeNotAllowed)
base = base.sons[0]
addSonSkipIntLit(result, base)
of mRef: result = semAnyRef(c, n, tyRef, prev)
of mPtr: result = semAnyRef(c, n, tyPtr, prev)
of mTuple: result = semTuple(c, n, prev)
else: result = semGeneric(c, n, s, prev)
of nkDotExpr:
var typeExpr = semExpr(c, n)
@@ -1370,10 +1391,7 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicType(m, tyTypeDesc, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mVoidType:
setMagicType(m, tyEmpty, 0)
# for historical reasons we conflate 'void' with 'empty' so that '@[]'
# has the type 'seq[void]'.
m.typ.flags.incl tfVoid
setMagicType(m, tyVoid, 0)
of mArray:
setMagicType(m, tyArray, 0)
of mOpenArray:

View File

@@ -162,7 +162,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
discard
of nkSym:
result.sym = replaceTypeVarsS(cl, n.sym)
if result.sym.typ.kind == tyEmpty:
if result.sym.typ.kind == tyVoid:
# don't add the 'void' field
result = newNode(nkRecList, n.info)
of nkRecWhen:
@@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# but we already raised an error!
rawAddSon(result, header.sons[i])
var newbody = replaceTypeVarsT(cl, lastSon(body))
let bbody = lastSon body
var newbody = replaceTypeVarsT(cl, bbody)
cl.skipTypedesc = oldSkipTypedesc
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags - tfInstClearedFlags
@@ -306,25 +307,31 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy)
attachedDeepCopy, 1)
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)
attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
# don't deal with '(): void':
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
if t.sons[0] != nil and t.sons[0].kind == tyVoid:
t.sons[0] = nil
for i in 1 .. <t.sonsLen:
# don't touch any memory unless necessary
if t.sons[i].kind == tyEmpty:
if t.sons[i].kind == tyVoid:
var pos = i
for j in i+1 .. <t.sonsLen:
if t.sons[j].kind != tyEmpty:
if t.sons[j].kind != tyVoid:
t.sons[pos] = t.sons[j]
t.n.sons[pos] = t.n.sons[j]
inc pos
@@ -504,6 +511,6 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
popInfoContext()
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): expr =
t: PType): untyped =
generateTypeInstance(p, pt, arg.info, t)

View File

@@ -22,7 +22,7 @@ type
TCandidateState* = enum
csEmpty, csMatch, csNoMatch
CandidateErrors* = seq[PSym]
CandidateErrors* = seq[(PSym,int)]
TCandidate* = object
c*: PContext
exactMatches*: int # also misused to prefer iters over procs
@@ -49,6 +49,7 @@ type
# a distrinct type
typedescMatched*: bool
isNoCall*: bool # misused for generic type instantiations C[T]
mutabilityProblem*: uint8 # tyVar mismatch
inheritancePenalty: int # to prefer closest father object type
errors*: CandidateErrors # additional clarifications to be displayed to the
# user if overload resolution fails
@@ -96,8 +97,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
c.calleeSym = nil
initIdTable(c.bindings)
proc put(t: var TIdTable, key, val: PType) {.inline.} =
idTablePut(t, key, val.skipIntLit)
proc put(c: var TCandidate, key, val: PType) {.inline.} =
idTablePut(c.bindings, key, val.skipIntLit)
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
binding: PNode, calleeScope = -1) =
@@ -129,7 +130,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
bound = makeTypeDesc(ctx, bound)
else:
bound = bound.skipTypes({tyTypeDesc})
put(c.bindings, formalTypeParam, bound)
put(c, formalTypeParam, bound)
proc newCandidate*(ctx: PContext, callee: PSym,
binding: PNode, calleeScope = -1): TCandidate =
@@ -220,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return
result = a.convMatches - b.convMatches
if result != 0: return
result = a.calleeScope - b.calleeScope
if result != 0: return
# the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty
if result != 0: return
# prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee)
# only as a last resort, consider scoping:
if result != 0: return
result = a.calleeScope - b.calleeScope
proc writeMatches*(c: TCandidate) =
writeLine(stdout, "exact matches: " & $c.exactMatches)
@@ -242,6 +244,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
for i in 1 .. <arg.len:
result.add(" | ")
result.add typeToString(arg[i].typ, prefer)
elif arg.typ == nil:
result = "void"
else:
result = arg.typ.typeToString(prefer)
@@ -253,15 +257,16 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
if n.sons[i].kind == nkExprEqExpr:
add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ")
if arg.typ.isNil:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
# XXX we really need to 'tryExpr' here!
arg = c.semOperand(c, n.sons[i].sons[1])
n.sons[i].typ = arg.typ
n.sons[i].sons[1] = arg
else:
if arg.typ.isNil:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
arg = c.semOperand(c, n.sons[i])
n.sons[i] = arg
if arg.typ.kind == tyError: return
if arg.typ != nil and arg.typ.kind == tyError: return
add(result, argTypeToString(arg, prefer))
if i != sonsLen(n) - 1: add(result, ", ")
@@ -360,6 +365,50 @@ proc isObjectSubtype(a, f: PType): int =
if t != nil:
result = depth
type
SkippedPtr = enum skippedNone, skippedRef, skippedPtr
proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
var r = t
# we're allowed to skip one level of ptr/ref:
var ptrs = 0
while r != nil:
case r.kind
of tyGenericInvocation:
r = r.sons[0]
of tyRef:
inc ptrs
skipped = skippedRef
r = r.lastSon
of tyPtr:
inc ptrs
skipped = skippedPtr
r = r.lastSon
of tyGenericBody, tyGenericInst:
r = r.lastSon
else:
break
if r.kind == tyObject and ptrs <= 1: result = r
proc isGenericSubtype(a, f: PType, d: var int): bool =
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
var askip = skippedNone
var fskip = skippedNone
var t = a.skipToObject(askip)
let r = f.skipToObject(fskip)
if r == nil: return false
var depth = 0
# XXX sameObjectType can return false here. Need to investigate
# why that is but sameObjectType does way too much work here anyway.
while t != nil and r.sym != t.sym and askip == fskip:
t = t.sons[0]
if t != nil: t = t.skipToObject(askip)
else: break
inc depth
if t != nil and askip == fskip:
d = depth
result = true
proc minRel(a, b: TTypeRelation): TTypeRelation =
if a <= b: result = a
else: result = b
@@ -513,7 +562,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
ff, a: PType): TTypeRelation =
var body = ff.skipTypes({tyUserTypeClassInst})
if c.inTypeClass > 20:
if c.inTypeClass > 4:
localError(body.n[3].info, $body.n[3] & " too nested for type matching")
return isNone
@@ -531,7 +580,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
typ = ff.sons[i]
param: PSym
template paramSym(kind): expr =
template paramSym(kind): untyped =
newSym(kind, typeParamName, body.sym, body.sym.info)
case typ.kind
@@ -598,6 +647,10 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
result = c.c.semExpr(c.c, instantiated)
template subtypeCheck() =
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
result = isNone
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# typeRel can be used to establish various relationships between types:
#
@@ -619,7 +672,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
assert(f != nil)
if f.kind == tyExpr:
if aOrig != nil: put(c.bindings, f, aOrig)
if aOrig != nil: put(c, f, aOrig)
return isGeneric
assert(aOrig != nil)
@@ -640,10 +693,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
template bindingRet(res) =
if doBind:
let bound = aOrig.skipTypes({tyRange}).skipIntLit
if doBind: put(c.bindings, f, bound)
put(c, f, bound)
return res
template considerPreviousT(body: stmt) {.immediate.} =
template considerPreviousT(body: untyped) =
var prev = PType(idTableGet(c.bindings, f))
if prev == nil: body
else: return typeRel(c, prev, a)
@@ -737,6 +790,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyVar:
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
else: result = typeRel(c, f.base, aOrig)
subtypeCheck()
of tyArray, tyArrayConstr:
# tyArrayConstr cannot happen really, but
# we wanna be safe here
@@ -746,7 +800,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if fRange.kind == tyGenericParam:
var prev = PType(idTableGet(c.bindings, fRange))
if prev == nil:
put(c.bindings, fRange, a.sons[0])
put(c, fRange, a.sons[0])
fRange = a
else:
fRange = prev
@@ -764,7 +818,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# we must correct for the off-by-one discrepancy between
# ranges and static params:
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
put(c.bindings, rangeStaticT, replacementT)
put(c, rangeStaticT, replacementT)
return isGeneric
let len = tryResolvingStaticExpr(c, fRange.n[1])
@@ -851,6 +905,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if sameDistinctTypes(f, a): result = isEqual
elif f.base.kind == tyAnything: result = isGeneric
elif c.coerceDistincts: result = typeRel(c, f.base, a)
elif a.kind == tyNil and f.base.kind in NilableTypes:
result = f.allowsNil
elif c.coerceDistincts: result = typeRel(c, f.base, a)
of tySet:
if a.kind == tySet:
@@ -867,6 +923,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
for i in 0..f.len-2:
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
result = typeRel(c, f.lastSon, a.lastSon)
subtypeCheck()
if result <= isConvertible: result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion
@@ -921,8 +978,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isConvertible
else: discard
of tyEmpty:
if a.kind == tyEmpty: result = isEqual
of tyEmpty, tyVoid:
if a.kind == f.kind: result = isEqual
of tyGenericInst:
result = typeRel(c, lastSon(f), a)
@@ -932,21 +989,26 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if a.kind == tyGenericInst and a.sons[0] == f:
bindingRet isGeneric
let ff = lastSon(f)
if ff != nil: result = typeRel(c, ff, a)
if ff != nil:
result = typeRel(c, ff, a)
of tyGenericInvocation:
var x = a.skipGenericAlias
var depth = 0
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
# simply no match for now:
discard
elif x.kind == tyGenericInst and
(f.sons[0] == x.sons[0]) and
((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and
(sonsLen(x) - 1 == sonsLen(f)):
for i in countup(1, sonsLen(f) - 1):
if x.sons[i].kind == tyGenericParam:
internalError("wrong instantiated type!")
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype:
# Workaround for regression #4589
if f.sons[i].kind != tyTypeDesc: return
c.inheritancePenalty += depth
result = isGeneric
else:
let genericBody = f.sons[0]
@@ -963,13 +1025,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
#
# we steal the generic parameters from the tyGenericBody:
for i in countup(1, sonsLen(f) - 1):
var x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
let x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
if x == nil:
discard "maybe fine (for eg. a==tyNil)"
elif x.kind in {tyGenericInvocation, tyGenericParam}:
internalError("wrong instantiated type!")
else:
put(c.bindings, f.sons[i], x)
put(c, f.sons[i], x)
of tyAnd:
considerPreviousT:
@@ -979,6 +1041,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if x < isSubtype: return isNone
# 'and' implies minimum matching result:
if x < result: result = x
if result > isGeneric: result = isGeneric
bindingRet result
of tyOr:
@@ -989,6 +1052,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# 'or' implies maximum matching result:
if x > result: result = x
if result >= isSubtype:
if result > isGeneric: result = isGeneric
bindingRet result
else:
result = isNone
@@ -1005,7 +1069,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
considerPreviousT:
var concrete = concreteType(c, a)
if concrete != nil and doBind:
put(c.bindings, f, concrete)
put(c, f, concrete)
return isGeneric
of tyBuiltInTypeClass:
@@ -1013,7 +1077,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
let targetKind = f.sons[0].kind
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
(targetKind in {tyProc, tyPointer} and a.kind == tyNil):
put(c.bindings, f, a)
put(c, f, a)
return isGeneric
else:
return isNone
@@ -1022,7 +1086,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
considerPreviousT:
result = matchUserTypeClass(c.c, c, f, aOrig)
if result == isGeneric:
put(c.bindings, f, a)
put(c, f, a)
of tyCompositeTypeClass:
considerPreviousT:
@@ -1038,7 +1102,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
result = typeRel(c, rootf.lastSon, a)
if result != isNone:
put(c.bindings, f, a)
put(c, f, a)
result = isGeneric
of tyGenericParam:
var x = PType(idTableGet(c.bindings, f))
@@ -1072,7 +1136,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if doBind and result notin {isNone, isGeneric}:
let concrete = concreteType(c, a)
if concrete == nil: return isNone
put(c.bindings, f, concrete)
put(c, f, concrete)
else:
result = isGeneric
@@ -1086,7 +1150,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if concrete == nil:
return isNone
if doBind:
put(c.bindings, f, concrete)
put(c, f, concrete)
elif result > isGeneric:
result = isGeneric
elif a.kind == tyEmpty:
@@ -1105,7 +1169,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if result != isNone and f.n != nil:
if not exprStructuralEquivalent(f.n, aOrig.n):
result = isNone
if result != isNone: put(c.bindings, f, aOrig)
if result != isNone: put(c, f, aOrig)
else:
result = isNone
elif prev.kind == tyStatic:
@@ -1133,7 +1197,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = typeRel(c, f.base, a.base)
if result != isNone:
put(c.bindings, f, a)
put(c, f, a)
else:
if tfUnresolved in f.flags:
result = typeRel(c, prev.base, a)
@@ -1151,7 +1215,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyStmt:
if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
put(c.bindings, f, aOrig)
put(c, f, aOrig)
result = isGeneric
of tyProxy:
@@ -1256,6 +1320,13 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if r == isGeneric:
result.typ = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
# bug #4545: allow the call to go through a 'var T':
let vt = result.sons[0].typ.sons[1]
if vt.kind == tyVar:
let x = result.sons[1]
let va = newNodeIT(nkHiddenAddr, x.info, vt)
va.add x
result.sons[1] = va
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
case r
@@ -1399,7 +1470,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isNone:
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
# do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
if a.kind in {tyProxy, tyUnknown}:
inc(m.genericMatches)
m.fauxMatch = a.kind
@@ -1420,6 +1491,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
m.baseTypeMatch = true
else:
result = userConvMatch(c, m, base(f), a, arg)
if result != nil: m.baseTypeMatch = true
proc paramTypesMatch*(m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode =
@@ -1532,13 +1604,13 @@ proc incrIndexType(t: PType) =
assert t.kind == tyArrayConstr
inc t.sons[0].n.sons[1].intVal
template isVarargsUntyped(x): expr =
template isVarargsUntyped(x): untyped =
x.kind == tyVarargs and x.sons[0].kind == tyExpr and
tfOldSchoolExprStmt notin x.sons[0].flags
proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var IntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} =
template checkConstraint(n: untyped) {.dirty.} =
if not formal.constraint.isNil:
if matchNodeKinds(formal.constraint, n):
# better match over other routines with no such restriction:
@@ -1549,6 +1621,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if formal.typ.kind == tyVar:
if not n.isLValue:
m.state = csNoMatch
m.mutabilityProblem = uint8(f-1)
return
var
@@ -1568,6 +1641,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
while a < n.len:
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
incl(marker, formal.position)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, container)
@@ -1630,6 +1704,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
# beware of the side-effects in 'prepareOperand'! So only do it for
# varargs matching. See tests/metatype/tstatic_overloading.
m.baseTypeMatch = false
incl(marker, formal.position)
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
@@ -1653,30 +1728,39 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch
return
m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if arg == nil:
m.state = csNoMatch
return
if m.baseTypeMatch:
#assert(container == nil)
if formal.typ.isVarargsUntyped:
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, container)
else:
incrIndexType(container.typ)
addSon(container, arg)
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
#if f != formalLen - 1: container = nil
# pick the formal from the end, so that 'x, y, varargs, z' works:
f = max(f, formalLen - n.len + a + 1)
addSon(container, n.sons[a])
else:
setSon(m.call, formal.position + 1, arg)
inc(f)
container = nil
m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if arg == nil:
m.state = csNoMatch
return
if m.baseTypeMatch:
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
else:
incrIndexType(container.typ)
addSon(container, arg)
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
#if f != formalLen - 1: container = nil
# pick the formal from the end, so that 'x, y, varargs, z' works:
f = max(f, formalLen - n.len + a + 1)
else:
setSon(m.call, formal.position + 1, arg)
inc(f)
container = nil
checkConstraint(n.sons[a])
inc(a)
@@ -1707,15 +1791,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if formal.ast == nil:
if formal.typ.kind == tyVarargs:
var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
container, m, c))
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
else:
# no default value
m.state = csNoMatch
break
else:
# use default value:
setSon(m.call, formal.position + 1, copyTree(formal.ast))
var def = copyTree(formal.ast)
if def.kind == nkNilLit:
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
setSon(m.call, formal.position + 1, def)
inc(f)
proc argtypeMatches*(c: PContext, f, a: PType): bool =
@@ -1728,16 +1815,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
result = res != nil
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.procvar.} =
op: TTypeAttachedOp; col: int): PSym {.procvar.} =
var m: TCandidate
initCandidate(c, m, dc.typ)
var f = dc.typ.sons[1]
if col >= dc.typ.len:
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
return nil
var f = dc.typ.sons[col]
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'")
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
else:
result = c.semGenerateInstance(c, dc, m.bindings, info)
assert sfFromGeneric in result.flags
@@ -1745,7 +1835,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
include suggest
when not declared(tests):
template tests(s: stmt) {.immediate.} = discard
template tests(s: untyped) = discard
tests:
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())

View File

@@ -138,7 +138,7 @@ proc suggestField(c: PContext, s: PSym, outputs: var int) =
suggestResult(symToSuggest(s, isLocal=true, $ideSug, 100))
inc outputs
template wholeSymTab(cond, section: expr) {.immediate.} =
template wholeSymTab(cond, section: untyped) =
var isLocal = true
for scope in walkScopes(c.currentScope):
if scope == c.topLevelScope: isLocal = false
@@ -393,6 +393,8 @@ proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} =
proc markUsed(info: TLineInfo; s: PSym) =
incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil:
incl(s.owner.flags, sfUsed)
if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)

View File

@@ -95,7 +95,7 @@ proc getCurrOwner(c: PTransf): PSym =
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
r.typ = skipTypes(typ, {tyGenericInst})
r.typ = typ #skipTypes(typ, {tyGenericInst})
incl(r.flags, sfFromGeneric)
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly:
@@ -204,14 +204,8 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
if it.sons[0].kind != nkSym:
internalError(it.info, "transformConstSection")
if sfFakeConst in it[0].sym.flags:
var b = newNodeI(nkConstDef, it.info)
addSon(b, it[0])
addSon(b, ast.emptyNode) # no type description
addSon(b, transform(c, it[2]).PNode)
result[i] = PTransNode(b)
else:
result[i] = PTransNode(it)
result[i] = PTransNode(it)
proc hasContinue(n: PNode): bool =
case n.kind
@@ -414,8 +408,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar)
result[0] = transform(c, n.sons[1])
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
of tyFloat..tyFloat128:
# XXX int64 -> float conversion?
if skipTypes(n.typ, abstractVar).kind == tyRange:
@@ -480,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
type
TPutArgInto = enum
paDirectMapping, paFastAsgn, paVarAsgn
paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
# This analyses how to treat the mapping "formal <-> arg" in an
# inline context.
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
if arg.kind == nkStmtListExpr:
return paComplexOpenarray
return paDirectMapping # XXX really correct?
# what if ``arg`` has side-effects?
case arg.kind
@@ -575,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
idNodeTablePut(newC.mapping, formal, arg)
# XXX BUG still not correct if the arg has a side effect!
of paComplexOpenarray:
let typ = newType(tySequence, formal.owner)
addSonSkipIntLit(typ, formal.typ.sons[0])
var temp = newTemp(c, typ, formal.info)
addVar(v, temp)
add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
idNodeTablePut(newC.mapping, formal, temp)
var body = iter.getBody.copyTree
pushInfoContext(n.info)
# XXX optimize this somehow. But the check "c.inlining" is not correct:

View File

@@ -103,14 +103,16 @@ proc getMagic*(op: PNode): TMagic =
else: result = mNone
else: result = mNone
proc treeToSym*(t: PNode): PSym =
result = t.sym
proc isConstExpr*(n: PNode): bool =
result = (n.kind in
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
proc isCaseObj*(n: PNode): bool =
if n.kind == nkRecCase: return true
for i in 0..<safeLen(n):
if n[i].isCaseObj: return true
proc isDeepConstExpr*(n: PNode): bool =
case n.kind
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
@@ -119,11 +121,14 @@ proc isDeepConstExpr*(n: PNode): bool =
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len:
for i in ord(n.kind == nkObjConstr) .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false
# XXX once constant objects are supported by the codegen this needs to be
# weakened:
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
if n.typ.isNil: result = true
else:
let t = n.typ.skipTypes({tyGenericInst, tyDistinct})
if t.kind in {tyRef, tyPtr}: return false
if t.kind != tyObject or not isCaseObj(t.n):
result = true
else: discard
proc flattenTreeAux(d, a: PNode, op: TMagic) =

View File

@@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool
proc enumHasHoles*(t: PType): bool
const
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
# replace with typedescX
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable, tyTypeDesc}
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
@@ -61,6 +63,7 @@ const
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
tyTypeDesc}
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc}
@@ -148,10 +151,12 @@ proc skipGeneric(t: PType): PType =
proc isOrdinalType(t: PType): bool =
assert(t != nil)
# caution: uint, uint64 are no ordinal types!
result = t.kind in {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} or
(t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
isOrdinalType(t.sons[0])
const
# caution: uint, uint64 are no ordinal types!
baseKinds = {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum}
parentKinds = {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst,
tyDistinct}
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
proc enumHasHoles(t: PType): bool =
var b = t
@@ -407,7 +412,8 @@ const
"!", "varargs[$1]", "iter[$1]", "Error Type",
"BuiltInTypeClass", "UserTypeClass",
"UserTypeClassInst", "CompositeTypeClass",
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
"void"]
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
@@ -540,7 +546,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
else:
result.add typeToString(t.sons[0])
of tyRange:
result = "range " & rangeToStr(t.n)
result = "range "
if t.n != nil and t.n.kind == nkRange:
result.add rangeToStr(t.n)
if prefer != preferExported:
result.add("(" & typeToString(t.sons[0]) & ")")
of tyProc:
@@ -727,6 +735,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
result = paramsNotEqual
proc sameConstraints(a, b: PNode): bool =
if isNil(a) and isNil(b): return true
internalAssert a.len == b.len
for i in 1 .. <a.len:
if not exprStructuralEquivalent(a[i].sym.constraint,
@@ -799,8 +808,10 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
result = x.name.id == y.name.id
if not result: break
else: internalError(a.n.info, "sameTuple")
elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
result = false
template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
template ifFastObjectTypeCheckFailed(a, b: PType, body: untyped) =
if tfFromGeneric notin a.flags + b.flags:
# fast case: id comparison suffices:
result = a.id == b.id
@@ -908,7 +919,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
while a.kind == tyDistinct: a = a.sons[0]
if a.kind != b.kind: return false
if x.kind == tyGenericInst:
# this is required by tunique_type but makes no sense really:
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias
@@ -922,7 +934,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
case a.kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyStmt, tyExpr:
tyInt..tyBigNum, tyStmt, tyExpr, tyVoid:
result = sameFlags(a, b)
of tyStatic, tyFromExpr:
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
@@ -1108,7 +1120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = nil
of tyExpr, tyStmt, tyStatic:
if kind notin {skParam, skResult}: result = t
of tyEmpty:
of tyVoid:
if taField notin flags: result = t
of tyTypeClasses:
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
@@ -1153,7 +1165,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
if result != nil: break
if result.isNil and t.n != nil:
result = typeAllowedNode(marker, t.n, kind, flags)
of tyProxy:
of tyProxy, tyEmpty:
# for now same as error node; we say it's a valid type as it should
# prevent cascading errors:
result = nil
@@ -1313,6 +1325,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyTypeDesc:
result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion
of tyStatic:
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
else: result = szUnknownSize
else:
#internalError("computeSizeAux()")
result = szUnknownSize
@@ -1448,6 +1463,18 @@ proc skipConv*(n: PNode): PNode =
result = n.sons[1]
else: discard
proc skipHidden*(n: PNode): PNode =
result = n
while true:
case result.kind
of nkHiddenStdConv, nkHiddenSubConv:
if result.sons[1].typ.classify == result.typ.classify:
result = result.sons[1]
else: break
of nkHiddenDeref, nkHiddenAddr:
result = result.sons[0]
else: break
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
@@ -1493,3 +1520,12 @@ proc skipHiddenSubConv*(n: PNode): PNode =
result.typ = dest
else:
result = n
proc typeMismatch*(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
let named = typeToString(formal)
let desc = typeToString(formal, preferDesc)
let x = if named == desc: named else: named & " = " & desc
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
typeToString(actual) & ") " &
`%`(msgKindToString(errButExpectedX), [x]))

View File

@@ -10,7 +10,9 @@
## This file implements the new evaluation engine for Nim code.
## An instruction is 1-3 int32s in memory, it is a register based VM.
const debugEchoCode = false
const
debugEchoCode = false
traceCode = debugEchoCode
import ast except getstr
@@ -90,38 +92,38 @@ when not defined(nimComputedGoto):
proc myreset(n: var TFullReg) = reset(n)
template ensureKind(k: expr) {.immediate, dirty.} =
template ensureKind(k: untyped) {.dirty.} =
if regs[ra].kind != k:
myreset(regs[ra])
regs[ra].kind = k
template decodeB(k: expr) {.immediate, dirty.} =
template decodeB(k: untyped) {.dirty.} =
let rb = instr.regB
ensureKind(k)
template decodeBC(k: expr) {.immediate, dirty.} =
template decodeBC(k: untyped) {.dirty.} =
let rb = instr.regB
let rc = instr.regC
ensureKind(k)
template declBC() {.immediate, dirty.} =
template declBC() {.dirty.} =
let rb = instr.regB
let rc = instr.regC
template decodeBImm(k: expr) {.immediate, dirty.} =
template decodeBImm(k: untyped) {.dirty.} =
let rb = instr.regB
let imm = instr.regC - byteExcess
ensureKind(k)
template decodeBx(k: expr) {.immediate, dirty.} =
template decodeBx(k: untyped) {.dirty.} =
let rbx = instr.regBx - wordExcess
ensureKind(k)
template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b)
# XXX fix minor 'shallowCopy' overloading bug in compiler
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
if x.node.isNil:
if x.node.isNil or not keepNode:
x.node = newNode(nkStrLit)
elif x.node.kind == nkNilLit and keepNode:
when defined(useNodeIds):
@@ -160,7 +162,7 @@ proc moveConst(x: var TFullReg, y: TFullReg) =
# this seems to be the best way to model the reference semantics
# of system.NimNode:
template asgnRef(x, y: expr) = moveConst(x, y)
template asgnRef(x, y: untyped) = moveConst(x, y)
proc copyValue(src: PNode): PNode =
if src == nil or nfIsRef in src.flags:
@@ -231,7 +233,7 @@ proc regToNode(x: TFullReg): PNode =
of rkRegisterAddr: result = regToNode(x.regAddr[])
of rkNodeAddr: result = x.nodeAddr[]
template getstr(a: expr): expr =
template getstr(a: untyped): untyped =
(if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
proc pushSafePoint(f: PStackFrame; pc: int) =
@@ -404,7 +406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let instr = c.code[pc]
let ra = instr.regA
#if c.traceActive:
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
when traceCode:
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
# message(c.debug[pc], warnUser, "Trace")
case instr.opcode
@@ -542,7 +545,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].node.kind == nkRefTy:
regs[ra].node = regs[rb].node.sons[0]
else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'")
stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
else:
stackTrace(c, tos, pc, errNilAccess)
of opcWrDeref:
@@ -1182,19 +1185,35 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNGetType:
let rb = instr.regB
let rc = instr.regC
if rc == 0:
case rc:
of 0:
# getType opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
else:
of 1:
# typeKind opcode:
ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind)
#else:
# stackTrace(c, tos, pc, errGenerated, "node has no type")
of 2:
# getTypeInst opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
else:
# getTypeImpl opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
of opcNStrVal:
decodeB(rkNode)
createStr regs[ra]
@@ -1554,7 +1573,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
var evalMacroCounter: int
proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# XXX GlobalError() is ugly here, but I don't know a better solution for now
# XXX globalError() is ugly here, but I don't know a better solution for now
inc(evalMacroCounter)
if evalMacroCounter > 100:
globalError(n.info, errTemplateInstantiationTooNested)
@@ -1584,7 +1603,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# return value:
tos.slots[0].kind = rkNode
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
tos.slots[0].node = newNodeI(nkEmpty, n.info)
# setup parameters:
for i in 1.. <sym.typ.len:
@@ -1604,4 +1623,3 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
if cyclicTree(result): globalError(n.info, errCyclicTree)
dec(evalMacroCounter)
c.callsite = nil
#debug result

View File

@@ -230,10 +230,10 @@ const
slotSomeTemp* = slotTempUnknown
relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
template regB*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32)
template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int
template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int
template jmpDiff*(x: TInstr): int {.immediate.} = regBx(x) - wordExcess
template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
import ast, types, msgs, osproc, streams, options, idents, securehash
import ast, types, msgs, os, osproc, streams, options, idents, securehash
proc readOutput(p: Process): string =
result = ""
@@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string =
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
try:
let filename = file.findFile
var filename = parentDir(info.toFullPath) / file
if not fileExists(filename):
filename = file.findFile
result = readFile(filename)
# we produce a fake include statement for every slurped filename, so that
# the module dependencies are accurate:
@@ -61,123 +63,249 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
localError(info, errCannotOpenFile, file)
result = ""
proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
let sym = newSym(skType, getIdent(name), t.owner, info)
sym.magic = m
sym.typ = t
result = newSymNode(sym)
result.typ = t
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
proc mapTypeToAstX(t: PType; info: TLineInfo;
inst=false; allowRecursionX=false): PNode
proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo;
inst=false): PNode =
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicTypeX(name, t, info)
result.add atomicTypeX(name, m, t, info)
for i in 0 .. < t.len:
if t.sons[i] == nil:
let void = atomicTypeX("void", t, info)
void.typ = newType(tyEmpty, t.owner)
let void = atomicTypeX("void", mVoid, t, info)
void.typ = newType(tyVoid, t.owner)
result.add void
else:
result.add mapTypeToAst(t.sons[i], info)
result.add mapTypeToAstX(t.sons[i], info, inst)
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
template atomicType(name): expr = atomicTypeX(name, t, info)
proc objectNode(n: PNode): PNode =
if n.kind == nkSym:
result = newNodeI(nkIdentDefs, n.info)
result.add n # name
result.add mapTypeToAstX(n.sym.typ, n.info, true, false) # type
result.add ast.emptyNode # no assigned value
else:
result = copyNode(n)
for i in 0 ..< n.safeLen:
result.add objectNode(n[i])
proc mapTypeToAstX(t: PType; info: TLineInfo;
inst=false; allowRecursionX=false): PNode =
var allowRecursion = allowRecursionX
template atomicType(name, m): untyped = atomicTypeX(name, m, t, info)
template mapTypeToAst(t,info): untyped = mapTypeToAstX(t, info, inst)
template mapTypeToAstR(t,info): untyped = mapTypeToAstX(t, info, inst, true)
template mapTypeToAst(t,i,info): untyped =
if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst)
else: ast.emptyNode
template mapTypeToBracket(name, m, t, info): untyped =
mapTypeToBracketX(name, m, t, info, inst)
template newNodeX(kind): untyped =
newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
template newIdent(s): untyped =
var r = newNodeX(nkIdent)
r.add !s
r
template newIdentDefs(n,t): untyped =
var id = newNodeX(nkIdentDefs)
id.add n # name
id.add mapTypeToAst(t, info) # type
id.add ast.emptyNode # no assigned value
id
template newIdentDefs(s): untyped = newIdentDefs(s, s.typ)
if inst:
if t.sym != nil: # if this node has a symbol
if allowRecursion: # getTypeImpl behavior: turn off recursion
allowRecursion = false
else: # getTypeInst behavior: return symbol
return atomicType(t.sym.name.s, t.sym.magic)
case t.kind
of tyNone: result = atomicType("none")
of tyBool: result = atomicType("bool")
of tyChar: result = atomicType("char")
of tyNil: result = atomicType("nil")
of tyExpr: result = atomicType("expr")
of tyStmt: result = atomicType("stmt")
of tyEmpty: result = atomicType"void"
of tyNone: result = atomicType("none", mNone)
of tyBool: result = atomicType("bool", mBool)
of tyChar: result = atomicType("char", mChar)
of tyNil: result = atomicType("nil", mNil)
of tyExpr: result = atomicType("expr", mExpr)
of tyStmt: result = atomicType("stmt", mStmt)
of tyVoid: result = atomicType("void", mVoid)
of tyEmpty: result = atomicType("empty", mNone)
of tyArrayConstr, tyArray:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("array")
result.add mapTypeToAst(t.sons[0], info)
result.add atomicType("array", mArray)
if inst and t.sons[0].kind == tyRange:
var rng = newNodeX(nkInfix)
rng.add newIdentNode(getIdent(".."), info)
rng.add t.sons[0].n.sons[0].copyTree
rng.add t.sons[0].n.sons[1].copyTree
result.add rng
else:
result.add mapTypeToAst(t.sons[0], info)
result.add mapTypeToAst(t.sons[1], info)
of tyTypeDesc:
if t.base != nil:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("typeDesc")
result.add atomicType("typeDesc", mTypeDesc)
result.add mapTypeToAst(t.base, info)
else:
result = atomicType"typeDesc"
result = atomicType("typeDesc", mTypeDesc)
of tyGenericInvocation:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
for i in 0 .. < t.len:
result.add mapTypeToAst(t.sons[i], info)
of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
of tyGenericInst:
if inst:
if allowRecursion:
result = mapTypeToAstR(t.lastSon, info)
else:
result = newNodeX(nkBracketExpr)
result.add mapTypeToAst(t.lastSon, info)
for i in 1 .. < t.len-1:
result.add mapTypeToAst(t.sons[i], info)
else:
result = mapTypeToAst(t.lastSon, info)
of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
result = mapTypeToAst(t.lastSon, info)
of tyDistinct:
if allowRecursion:
result = mapTypeToBracket("distinct", t, info)
if inst:
result = newNodeX(nkDistinctTy)
result.add mapTypeToAst(t.sons[0], info)
else:
result = atomicType(t.sym.name.s)
of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
of tyObject:
if allowRecursion:
result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
if t.sons[0] == nil:
result.add ast.emptyNode
if allowRecursion or t.sym == nil:
result = mapTypeToBracket("distinct", mDistinct, t, info)
else:
result.add mapTypeToAst(t.sons[0], info)
result.add copyTree(t.n)
result = atomicType(t.sym.name.s, t.sym.magic)
of tyGenericParam, tyForward:
result = atomicType(t.sym.name.s, t.sym.magic)
of tyObject:
if inst:
result = newNodeX(nkObjectTy)
result.add ast.emptyNode # pragmas not reconstructed yet
if t.sons[0] == nil: result.add ast.emptyNode # handle parent object
else:
var nn = newNodeX(nkOfInherit)
nn.add mapTypeToAst(t.sons[0], info)
result.add nn
if t.n.len > 0:
result.add objectNode(t.n)
else:
result.add ast.emptyNode
else:
result = atomicType(t.sym.name.s)
if allowRecursion or t.sym == nil:
result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
result.add ast.emptyNode
if t.sons[0] == nil:
result.add ast.emptyNode
else:
result.add mapTypeToAst(t.sons[0], info)
result.add copyTree(t.n)
else:
result = atomicType(t.sym.name.s, t.sym.magic)
of tyEnum:
result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t)
result.add copyTree(t.n)
of tyTuple: result = mapTypeToBracket("tuple", t, info)
of tySet: result = mapTypeToBracket("set", t, info)
of tyPtr: result = mapTypeToBracket("ptr", t, info)
of tyRef: result = mapTypeToBracket("ref", t, info)
of tyVar: result = mapTypeToBracket("var", t, info)
of tySequence: result = mapTypeToBracket("seq", t, info)
of tyProc: result = mapTypeToBracket("proc", t, info)
of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
of tyTuple:
if inst:
result = newNodeX(nkTupleTy)
for s in t.n.sons:
result.add newIdentDefs(s)
else:
result = mapTypeToBracket("tuple", mTuple, t, info)
of tySet: result = mapTypeToBracket("set", mSet, t, info)
of tyPtr:
if inst:
result = newNodeX(nkPtrTy)
result.add mapTypeToAst(t.sons[0], info)
else:
result = mapTypeToBracket("ptr", mPtr, t, info)
of tyRef:
if inst:
result = newNodeX(nkRefTy)
result.add mapTypeToAst(t.sons[0], info)
else:
result = mapTypeToBracket("ref", mRef, t, info)
of tyVar: result = mapTypeToBracket("var", mVar, t, info)
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
of tyProc:
if inst:
result = newNodeX(nkProcTy)
var fp = newNodeX(nkFormalParams)
if t.sons[0] == nil:
fp.add ast.emptyNode
else:
fp.add mapTypeToAst(t.sons[0], t.n[0].info)
for i in 1..<t.sons.len:
fp.add newIdentDefs(t.n[i], t.sons[i])
result.add fp
result.add ast.emptyNode # pragmas aren't reconstructed yet
else:
result = mapTypeToBracket("proc", mNone, t, info)
of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info)
of tyRange:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("range")
result.add atomicType("range", mRange)
result.add t.n.sons[0].copyTree
result.add t.n.sons[1].copyTree
of tyPointer: result = atomicType"pointer"
of tyString: result = atomicType"string"
of tyCString: result = atomicType"cstring"
of tyInt: result = atomicType"int"
of tyInt8: result = atomicType"int8"
of tyInt16: result = atomicType"int16"
of tyInt32: result = atomicType"int32"
of tyInt64: result = atomicType"int64"
of tyFloat: result = atomicType"float"
of tyFloat32: result = atomicType"float32"
of tyFloat64: result = atomicType"float64"
of tyFloat128: result = atomicType"float128"
of tyUInt: result = atomicType"uint"
of tyUInt8: result = atomicType"uint8"
of tyUInt16: result = atomicType"uint16"
of tyUInt32: result = atomicType"uint32"
of tyUInt64: result = atomicType"uint64"
of tyBigNum: result = atomicType"bignum"
of tyConst: result = mapTypeToBracket("const", t, info)
of tyMutable: result = mapTypeToBracket("mutable", t, info)
of tyVarargs: result = mapTypeToBracket("varargs", t, info)
of tyIter: result = mapTypeToBracket("iter", t, info)
of tyProxy: result = atomicType"error"
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
of tyPointer: result = atomicType("pointer", mPointer)
of tyString: result = atomicType("string", mString)
of tyCString: result = atomicType("cstring", mCString)
of tyInt: result = atomicType("int", mInt)
of tyInt8: result = atomicType("int8", mInt8)
of tyInt16: result = atomicType("int16", mInt16)
of tyInt32: result = atomicType("int32", mInt32)
of tyInt64: result = atomicType("int64", mInt64)
of tyFloat: result = atomicType("float", mFloat)
of tyFloat32: result = atomicType("float32", mFloat32)
of tyFloat64: result = atomicType("float64", mFloat64)
of tyFloat128: result = atomicType("float128", mFloat128)
of tyUInt: result = atomicType("uint", mUint)
of tyUInt8: result = atomicType("uint8", mUint8)
of tyUInt16: result = atomicType("uint16", mUint16)
of tyUInt32: result = atomicType("uint32", mUint32)
of tyUInt64: result = atomicType("uint64", mUint64)
of tyBigNum: result = atomicType("bignum", mNone)
of tyConst: result = mapTypeToBracket("const", mNone, t, info)
of tyMutable: result = mapTypeToBracket("mutable", mNone, t, info)
of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
of tyIter: result = mapTypeToBracket("iter", mNone, t, info)
of tyProxy: result = atomicType("error", mNone)
of tyBuiltInTypeClass:
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
of tyUserTypeClass:
result = mapTypeToBracket("concept", t, info)
result = mapTypeToBracket("concept", mNone, 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)
of tyNot: result = mapTypeToBracket("not", t, info)
of tyAnything: result = atomicType"anything"
of tyCompositeTypeClass:
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
of tyOr: result = mapTypeToBracket("or", mOr, t, info)
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
of tyAnything: result = atomicType("anything", mNone)
of tyStatic, tyFromExpr, tyFieldAccessor:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("static")
if t.n != nil:
result.add t.n.copyTree
if inst:
if t.n != nil: result = t.n.copyTree
else: result = atomicType("void", mVoid)
else:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("static", mNone)
if t.n != nil:
result.add t.n.copyTree
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAst(t, info, true)
result = mapTypeToAstX(t, info, false, true)
# the "Inst" version includes generic parameters in the resulting type tree
# and also tries to look like the corresponding Nim type declaration
proc opMapTypeInstToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAstX(t, info, true, false)
# the "Impl" version includes generic parameters in the resulting type tree
# and also tries to look like the corresponding Nim type implementation
proc opMapTypeImplToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAstX(t, info, true, true)

View File

@@ -102,6 +102,10 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
(b.uint32 shl 16'u32) or
(c.uint32 shl 24'u32)).TInstr
when false:
if ctx.code.len == 43:
writeStackTrace()
echo "generating ", opc
ctx.code.add(ins)
ctx.debug.add(n.info)
@@ -122,6 +126,11 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
# Applies `opc` to `bx` and stores it into register `a`
# `bx` must be signed and in the range [-32768, 32767]
when false:
if c.code.len == 43:
writeStackTrace()
echo "generating ", opc
if bx >= -32768 and bx <= 32767:
let ins = (opc.uint32 or a.uint32 shl 8'u32 or
(bx+wordExcess).uint32 shl 16'u32).TInstr
@@ -222,7 +231,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
proc freeTempRange(c: PCtx; start: TRegister, n: int) =
for i in start .. start+n-1: c.freeTemp(TRegister(i))
template withTemp(tmp, typ: expr, body: stmt) {.immediate, dirty.} =
template withTemp(tmp, typ, body: untyped) {.dirty.} =
var tmp = getTemp(c, typ)
body
c.freeTemp(tmp)
@@ -232,7 +241,7 @@ proc popBlock(c: PCtx; oldLen: int) =
c.patch(f)
c.prc.blocks.setLen(oldLen)
template withBlock(labl: PSym; body: stmt) {.immediate, dirty.} =
template withBlock(labl: PSym; body: untyped) {.dirty.} =
var oldLen {.gensym.} = c.prc.blocks.len
c.prc.blocks.add TBlock(label: labl, fixups: @[])
body
@@ -258,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
# stmt is different from 'void' in meta programming contexts.
# So we only set dest to -1 if 'void':
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
c.freeTemp(dest)
dest = -1
@@ -365,7 +374,7 @@ proc canonValue*(n: PNode): PNode =
proc rawGenLiteral(c: PCtx; n: PNode): int =
result = c.constants.len
assert(n.kind != nkCall)
#assert(n.kind != nkCall)
n.flags.incl nfAllConst
c.constants.add n.canonValue
internalAssert result < 0x7fff
@@ -488,12 +497,30 @@ proc genReturn(c: PCtx; n: PNode) =
gen(c, n.sons[0])
c.gABC(n, opcRet)
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
# opcLdConst is now always valid. We produce the necessary copy in the
# assignments now:
#var opc = opcLdConst
if dest < 0: dest = c.getTemp(n.typ)
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
let lit = genLiteral(c, n)
c.gABx(n, opcLdConst, dest, lit)
proc genCall(c: PCtx; n: PNode; dest: var TDest) =
# it can happen that due to inlining we have a 'n' that should be
# treated as a constant (see issue #537).
#if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode:
# genLit(c, n, dest)
# return
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
let x = c.getTempRange(n.len, slotTempUnknown)
# varargs need 'opcSetType' for the FFI support:
let fntyp = n.sons[0].typ
let fntyp = skipTypes(n.sons[0].typ, abstractInst)
for i in 0.. <n.len:
#if i > 0 and i < sonsLen(fntyp):
# let paramType = fntyp.n.sons[i]
# if paramType.typ.isCompileTimeOnly: continue
var r: TRegister = x+i
c.gen(n.sons[i], r)
if i >= fntyp.len:
@@ -570,16 +597,27 @@ proc genNew(c: PCtx; n: PNode) =
c.freeTemp(dest)
proc genNewSeq(c: PCtx; n: PNode) =
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
let t = n.sons[1].typ
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t)
else: c.genx(n.sons[1])
let tmp = c.genx(n.sons[2])
c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(
c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
abstractVar-{tyTypeDesc})))
c.gABx(n, opcNewSeq, tmp, 0)
c.freeTemp(tmp)
c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(dest)
proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
let t = n.typ
let tmp = c.getTemp(n.sons[1].typ)
c.gABx(n, opcLdNull, dest, c.genType(t))
c.gABx(n, opcLdImmInt, tmp, 0)
c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
abstractVar-{tyTypeDesc})))
c.gABx(n, opcNewSeq, tmp, 0)
c.freeTemp(tmp)
proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let tmp = c.genx(n.sons[1])
if dest < 0: dest = c.getTemp(n.typ)
@@ -626,8 +664,7 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types:
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
(t.kind == tyInt and t.size == 4):
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
@@ -704,6 +741,10 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc:
# don't do anything for lambda lifting conversions:
gen(c, arg, dest)
return
let tmp = c.genx(arg)
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opc, dest, tmp)
@@ -751,6 +792,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNewSeq:
unused(n, dest)
c.genNewSeq(n)
of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
of mNewString:
genUnaryABC(c, n, dest, opcNewStr)
# XXX buggy
@@ -804,7 +846,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)
of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
of mEqProc, mEqRef, mEqUntracedRef, mEqCString:
of mEqProc, mEqRef, mEqUntracedRef:
genBinaryABC(c, n, dest, opcEqRef)
of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
of mNot: genUnaryABC(c, n, dest, opcNot)
@@ -821,7 +863,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n.sons[1], dest)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
@@ -970,7 +1012,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNGetType:
let tmp = c.genx(n.sons[1])
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
let rc = case n[0].sym.name.s:
of "getType": 0
of "typeKind": 1
of "getTypeInst": 2
else: 3 # "getTypeImpl"
c.gABC(n, opcNGetType, dest, tmp, rc)
c.freeTemp(tmp)
#genUnaryABC(c, n, dest, opcNGetType)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
@@ -1117,7 +1164,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
if isAddr and (let m = canElimAddr(n); m != nil):
gen(c, m, dest, flags)
return
let newflags = if isAddr: flags+{gfAddrOf} else: flags
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
else: {gfAddrOf}
let newflags = if isAddr: flags+af else: flags
# consider:
# proc foo(f: var ref int) =
# f = new(int)
@@ -1132,7 +1182,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
if gfAddrOf notin flags and fitsRegister(n.typ):
c.gABC(n, opcNodeToReg, dest, dest)
elif isAddr and isGlobal(n.sons[0]):
gen(c, n.sons[0], dest, flags+{gfAddrOf})
gen(c, n.sons[0], dest, flags+af)
else:
let tmp = c.genx(n.sons[0], newflags)
if dest < 0: dest = c.getTemp(n.typ)
@@ -1215,7 +1265,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
proc isTemp(c: PCtx; dest: TDest): bool =
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
template needsAdditionalCopy(n): expr =
template needsAdditionalCopy(n): untyped =
not c.isTemp(dest) and not fitsRegister(n.typ)
proc skipDeref(n: PNode): PNode =
@@ -1286,15 +1336,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
let dest = c.genx(le, {gfAddrOf})
genAsgn(c, dest, ri, requiresCopy)
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
# opcLdConst is now always valid. We produce the necessary copy in the
# assignments now:
#var opc = opcLdConst
if dest < 0: dest = c.getTemp(n.typ)
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
let lit = genLiteral(c, n)
c.gABx(n, opcLdConst, dest, lit)
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
var n = newNode(nkType)
n.typ = t
@@ -1321,10 +1362,11 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
# var decls{.compileTime.}: seq[NimNode] = @[]
let dest = c.getTemp(s.typ)
c.gABx(n, opcLdGlobal, dest, s.position)
let tmp = c.genx(s.ast)
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
c.freeTemp(dest)
c.freeTemp(tmp)
if s.ast != nil:
let tmp = c.genx(s.ast)
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
c.freeTemp(dest)
c.freeTemp(tmp)
proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
let s = n.sym
@@ -1361,7 +1403,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
# see tests/t99bott for an example that triggers it:
cannotEval(n)
template needsRegLoad(): expr =
template needsRegLoad(): untyped =
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
@@ -1447,12 +1489,12 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyObject:
result = newNodeIT(nkObjConstr, info, t)
result.add(newNodeIT(nkEmpty, info, t))
getNullValueAux(t.n, result)
# initialize inherited fields:
var base = t.sons[0]
while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result)
base = base.sons[0]
getNullValueAux(t.n, result)
of tyArray, tyArrayConstr:
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
@@ -1655,10 +1697,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of skType:
genTypeLit(c, s.typ, dest)
of skGenericParam:
if c.prc.sym.kind == skMacro:
if c.prc.sym != nil and c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags)
else:
internalError(n.info, "cannot generate code for: " & s.name.s)
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
of nkCallKinds:
@@ -1736,9 +1778,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of declarativeDefs:
unused(n, dest)
of nkLambdaKinds:
let s = n.sons[namePos].sym
discard genProc(c, s)
genLit(c, n.sons[namePos], dest)
#let s = n.sons[namePos].sym
#discard genProc(c, s)
genLit(c, newSymNode(n.sons[namePos].sym), dest)
of nkChckRangeF, nkChckRange64, nkChckRange:
let
tmp0 = c.genx(n.sons[0])
@@ -1766,6 +1808,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genConv(c, n, n.sons[1], dest, opcCast)
else:
globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
of nkTypeOfExpr:
genTypeLit(c, n.typ, dest)
else:
globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
@@ -1865,8 +1909,8 @@ proc optimizeJumps(c: PCtx; start: int) =
else: discard
proc genProc(c: PCtx; s: PSym): int =
let x = s.ast.sons[optimizedCodePos]
if x.kind == nkEmpty:
var x = s.ast.sons[miscPos]
if x.kind == nkEmpty or x[0].kind == nkEmpty:
#if s.name.s == "outterMacro" or s.name.s == "innerProc":
# echo "GENERATING CODE FOR ", s.name.s
let last = c.code.len-1
@@ -1877,7 +1921,11 @@ proc genProc(c: PCtx; s: PSym): int =
c.debug.setLen(last)
#c.removeLastEof
result = c.code.len+1 # skip the jump instruction
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
if x.kind == nkEmpty:
x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode)
else:
x.sons[0] = newIntNode(nkIntLit, result)
s.ast.sons[miscPos] = x
# thanks to the jmp we can add top level statements easily and also nest
# procs easily:
let body = s.getBody
@@ -1912,4 +1960,4 @@ proc genProc(c: PCtx; s: PSym): int =
c.prc = oldPrc
else:
c.prc.maxSlots = s.offset
result = x.intVal.int
result = x[0].intVal.int

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
template setX(k, field) {.immediate, dirty.} =
template setX(k, field) {.dirty.} =
var s: seq[TFullReg]
move(s, cast[seq[TFullReg]](a.slots))
if s[a.ra].kind != k:
@@ -48,7 +48,7 @@ proc setResult*(a: VmArgs; v: seq[string]) =
for x in v: n.add newStrNode(nkStrLit, x)
s[a.ra].node = n
template getX(k, field) {.immediate, dirty.} =
template getX(k, field) {.dirty.} =
doAssert i < a.rc-1
let s = cast[seq[TFullReg]](a.slots)
doAssert s[i+a.rb+1].kind == k

View File

@@ -15,31 +15,36 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
from os import getEnv, existsEnv, dirExists, fileExists, walkDir
template mathop(op) {.immediate, dirty.} =
template mathop(op) {.dirty.} =
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
template osop(op) {.immediate, dirty.} =
template osop(op) {.dirty.} =
registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
template systemop(op) {.immediate, dirty.} =
template systemop(op) {.dirty.} =
registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
template wrap1f(op) {.immediate, dirty.} =
template wrap1f_math(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getFloat(a, 0)))
mathop op
template wrap2f(op) {.immediate, dirty.} =
template wrap2f_math(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
mathop op
template wrap1s(op) {.immediate, dirty.} =
template wrap1s_os(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getString(a, 0)))
osop op
template wrap2svoid(op) {.immediate, dirty.} =
template wrap1s_system(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getString(a, 0)))
systemop op
template wrap2svoid_system(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
op(getString(a, 0), getString(a, 1))
systemop op
@@ -55,34 +60,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
newStrNode(nkStrLit, f))
proc registerAdditionalOps*(c: PCtx) =
wrap1f(sqrt)
wrap1f(ln)
wrap1f(log10)
wrap1f(log2)
wrap1f(exp)
wrap1f(round)
wrap1f(arccos)
wrap1f(arcsin)
wrap1f(arctan)
wrap2f(arctan2)
wrap1f(cos)
wrap1f(cosh)
wrap2f(hypot)
wrap1f(sinh)
wrap1f(sin)
wrap1f(tan)
wrap1f(tanh)
wrap2f(pow)
wrap1f(trunc)
wrap1f(floor)
wrap1f(ceil)
wrap2f(fmod)
wrap1f_math(sqrt)
wrap1f_math(ln)
wrap1f_math(log10)
wrap1f_math(log2)
wrap1f_math(exp)
wrap1f_math(round)
wrap1f_math(arccos)
wrap1f_math(arcsin)
wrap1f_math(arctan)
wrap2f_math(arctan2)
wrap1f_math(cos)
wrap1f_math(cosh)
wrap2f_math(hypot)
wrap1f_math(sinh)
wrap1f_math(sin)
wrap1f_math(tan)
wrap1f_math(tanh)
wrap2f_math(pow)
wrap1f_math(trunc)
wrap1f_math(floor)
wrap1f_math(ceil)
wrap2f_math(fmod)
wrap1s(getEnv)
wrap1s(existsEnv)
wrap1s(dirExists)
wrap1s(fileExists)
wrap2svoid(writeFile)
wrap1s_os(getEnv)
wrap1s_os(existsEnv)
wrap1s_os(dirExists)
wrap1s_os(fileExists)
wrap2svoid_system(writeFile)
wrap1s_system(readFile)
systemop getCurrentExceptionMsg
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))

View File

@@ -36,6 +36,7 @@ type
wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks,
wIntDefine, wStrDefine,
wDestroy,
@@ -121,7 +122,7 @@ const
":", "::", "=", ".", "..",
"*", "-",
"magic", "thread", "final", "profiler", "objchecks",
"magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine",
"destroy",

View File

@@ -23,10 +23,6 @@ arm.linux.gcc.linkerexe = "arm-linux-gcc"
mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
@if not nimfix:
cs:partial
@end
path="$lib/deprecated/core"
path="$lib/deprecated/pure"
path="$lib/pure/collections"
@@ -44,6 +40,11 @@ path="$lib/pure"
@if nimbabel:
nimblepath="$home/.nimble/pkgs/"
@if not windows:
nimblepath="/opt/nimble/pkgs/"
@else:
# TODO:
@end
@end
@if release or quick:
@@ -163,10 +164,5 @@ vcc.options.always = "/nologo"
vcc.options.speed = "/O2 /arch:SSE2"
vcc.options.size = "/O1"
# Configuration for the Digital Mars C/C++ compiler:
@if windows:
dmc.path = r"$nimrod\dist\dm\bin"
@end
# Configuration for the Tiny C Compiler:
tcc.options.always = "-w"

View File

@@ -1,5 +1,5 @@
# This is the config file for the documentation generator.
# (c) 2012 Andreas Rumpf
# (c) 2016 Andreas Rumpf
# Feel free to edit the templates as you need. If you modify this file, it
# might be worth updating the hardcoded values in packages/docutils/rstgen.nim
@@ -1235,10 +1235,46 @@ dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator
background-repeat: no-repeat;
background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
margin-bottom: -5px; }
div.pragma {
display: none;
}
span.pragmabegin {
cursor: pointer;
}
span.pragmaend {
cursor: pointer;
}
</style>
<script type="text/javascript">
function togglepragma(d) {
if (d.style.display != 'inline')
d.style.display = 'inline';
else
d.style.display = 'none';
}
function main() {
var elements = document.getElementsByClassName("pragmabegin");
for (var i = 0; i < elements.length; ++i) {
var e = elements[i];
e.onclick = function(event) {
togglepragma(event.target.nextSibling);
};
}
var elements = document.getElementsByClassName("pragmaend");
for (var i = 0; i < elements.length; ++i) {
var e = elements[i];
e.onclick = function(event) {
togglepragma(event.target.previousSibling);
};
}
}
</script>
</head>
<body>
<body onload="main()">
<div class="document" id="documentId">
<div class="container">
<h1 class="title">$title</h1>

View File

@@ -6,6 +6,7 @@ Advanced commands:
//rst2html convert a reStructuredText file to HTML
//rst2tex convert a reStructuredText file to TeX
//jsondoc extract the documentation to a json file
//jsondoc2 extract documentation to a json file (uses doc2)
//buildIndex build an index for the whole documentation
//run run the project (with Tiny C backend; buggy!)
//genDepend generate a DOT file containing the

View File

@@ -33,7 +33,7 @@ contains:
of nnkIdent:
ident: NimIdent ## the identifier
of nnkSym:
symbol: NimSymbol ## the symbol (after symbol lookup phase)
symbol: NimSym ## the symbol (after symbol lookup phase)
else:
sons: seq[NimNode] ## the node's sons (or children)

View File

@@ -110,8 +110,8 @@ interface <manual.html#foreign-function-interface>`_ mainly through the
`importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
*generic* way of making backend symbols available in Nim and is available
in all the target backends (JavaScript too). The C++ or Objective-C backends
have their respective `ImportCpp <nimc.html#importcpp-pragma>`_ and
`ImportObjC <nimc.html#importobjc-pragma>`_ pragmas to call methods from
have their respective `ImportCpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ pragmas to call methods from
classes.
Whenever you use any of these pragmas you need to integrate native code into
@@ -420,7 +420,7 @@ function directly will be able to use it since Nim's garbage collector has
not had a chance to run *yet*. This gives you enough time to make a copy for
the C side of the program, as calling any further Nim procs *might* trigger
garbage collection making the previously returned string garbage. Or maybe you
are `triggering yourself the collection <gc.html>`_.
are `yourself triggering the collection <gc.html>`_.
Custom data types

View File

@@ -11,7 +11,9 @@ Arguments:
arguments are passed to the program being run (if --run option is selected)
Options:
-p, --path:PATH add path to search paths
-d, --define:SYMBOL define a conditional symbol
-d, --define:SYMBOL(:VAL)
define a conditional symbol
(Optionally: Define the value for that symbol)
-u, --undef:SYMBOL undefine a conditional symbol
-f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off

View File

@@ -23,6 +23,10 @@ just like an ordinary procedure call with named or positional arguments. The
available parameters depend on the invoked filter. Before version 0.12.0 of
the language ``#!`` was used instead of ``#?``.
**Hint:** With ``--hint[codeBegin]:on```or ``--verbosity:2``
(or higher) Nim lists the processed code after each filter
application.
Pipe operator
=============
@@ -41,9 +45,6 @@ Filters can be combined with the ``|`` pipe operator::
Available filters
=================
**Hint:** With ``--verbosity:2`` (or higher) Nim lists the processed code
after each filter application.
Replace filter
--------------

View File

@@ -56,7 +56,7 @@ file as well). With this switch the GC supports the following operations:
.. code-block:: nim
proc GC_setMaxPause*(MaxPauseInUs: int)
proc GC_step*(us: int, strongAdvice = false)
proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
The unit of the parameters ``MaxPauseInUs`` and ``us`` is microseconds.
@@ -75,7 +75,13 @@ These two procs are the two modus operandi of the realtime GC:
This allows the GC to perform some work for up to ``us`` time. This is
useful to call in a main loop to ensure the GC can do its work. To
bind all GC activity to a ``GC_step`` call, deactivate the GC with
``GC_disable`` at program startup.
``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``,
GC will be forced to perform collection cycle. Otherwise, GC may decide not
to do anything, if there is not much garbage to collect.
You may also specify the current stack size via ``stackSize`` parameter.
It can improve performance, when you know that there are no unique Nim
references below certain point on the stack. Make sure the size you specify
is greater than the potential worst case size.
These procs provide a "best effort" realtime guarantee; in particular the
cycle collector is not aware of deadlines yet. Deactivate it to get more

View File

@@ -87,7 +87,7 @@ Collections and algorithms
* `sequtils <sequtils.html>`_
This module implements operations for the built-in seq type
which were inspired by functional programming languages.
String handling
---------------
@@ -97,9 +97,16 @@ String handling
case of a string, splitting a string into substrings, searching for
substrings, replacing substrings.
* `strmisc <strmisc.html>`_
This module contains uncommon string handling operations that do not
fit with the commonly used operations in strutils.
* `parseutils <parseutils.html>`_
This module contains helpers for parsing tokens, numbers, identifiers, etc.
* `strscans <strscans.html>`_
This module contains a ``scanf`` macro for convenient parsing of mini languages.
* `strtabs <strtabs.html>`_
The ``strtabs`` module implements an efficient hash table that is a mapping
from strings to strings. Supports a case-sensitive, case-insensitive and
@@ -199,6 +206,9 @@ Math libraries
* `mersenne <mersenne.html>`_
Mersenne twister random number generator.
* `random <random.html>`_
Fast and tiny random number generator.
* `stats <stats.html>`_
Statistical analysis
@@ -440,6 +450,10 @@ Regular expressions
This module contains procedures and operators for handling regular
expressions. The current implementation uses PCRE.
* `nre <nre.html>`_
Another implementation of procedures for using regular expressions. Also uses
PCRE.
Database support
----------------

View File

@@ -155,4 +155,4 @@ Exception hierarchy
The exception tree is defined in the `system <system.html>`_ module:
.. include:: exception_hierarchy_fragment.txt
.. include:: ../exception_hierarchy_fragment.txt

View File

@@ -16,11 +16,19 @@ spelled*:
.. code-block::
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
Note that this pragma is somewhat of a misnomer: Other backends will provide
Note that this pragma is somewhat of a misnomer: Other backends do provide
the same feature under the same name. Also, if one is interfacing with C++
the `ImportCpp pragma <nimc.html#importcpp-pragma>`_ and
the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
interfacing with Objective-C the `ImportObjC pragma
<nimc.html#importobjc-pragma>`_ can be used.
<manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
The string literal passed to ``importc`` can be a format string:
.. code-block:: Nim
proc p(s: cstring) {.importc: "prefix$1".}
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
is available and a literal dollar sign must be written as ``$$``.
Exportc pragma
@@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
.. code-block:: Nim
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
Note that this pragma is somewhat of a misnomer: Other backends will provide
Note that this pragma is somewhat of a misnomer: Other backends do provide
the same feature under the same name.
The string literal passed to ``exportc`` can be a format string:
.. code-block:: Nim
proc p(s: string) {.exportc: "prefix$1".} =
echo s
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
is available and a literal dollar sign must be written as ``$$``.
Extern pragma
-------------
@@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string:
proc p(s: string) {.extern: "prefix$1".} =
echo s
In the example the external name of ``p`` is set to ``prefixp``.
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
is available and a literal dollar sign must be written as ``$$``.
Bycopy pragma

View File

@@ -232,16 +232,6 @@ type signatures of the required operations, but since type inference and
default parameters are still applied in the provided block, it's also possible
to encode usage protocols that do not reveal implementation details.
As a special rule providing further convenience when writing concepts, any
type value appearing in a callable expression will be treated as a variable of
the designated type for overload resolution purposes, unless the type value was
passed in its explicit ``typedesc[T]`` form:
.. code-block:: nim
type
OutputStream = concept s
write(var s, string)
Much like generics, concepts are instantiated exactly
once for each tested type and any static code included within them is also
executed once.
@@ -303,7 +293,7 @@ definition):
var
lastId = 0
template genId*: expr =
template genId*: untyped =
bind lastId
inc(lastId)
lastId

Some files were not shown because too many files have changed in this diff Show More