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

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

5
.gitignore vendored
View file

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

View file

@ -10,7 +10,7 @@ addons:
- libgc-dev - libgc-dev
before_script: before_script:
- set -e - 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 - tar xvf fasm-1.71.39.tgz
- git clone --depth 1 https://github.com/nim-lang/csources.git - git clone --depth 1 https://github.com/nim-lang/csources.git
- cd csources - cd csources
@ -23,6 +23,7 @@ script:
- ./koch boot - ./koch boot
- ./koch boot -d:release - ./koch boot -d:release
- nim e install_nimble.nims - nim e install_nimble.nims
- nim e tests/test_nimscript.nims
- nimble update - nimble update
- nimble install zip - nimble install zip
- nimble install opengl - nimble install opengl

View file

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

View file

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

View file

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

View file

@ -259,6 +259,10 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
result = genArgNoParam(p, ri.sons[i][0]) result = genArgNoParam(p, ri.sons[i][0])
else: else:
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
else:
if tfVarargs notin typ.flags:
localError(ri.info, "wrong argument count")
result = nil
else: else:
result = genArgNoParam(p, ri.sons[i]) result = genArgNoParam(p, ri.sons[i])

View file

@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope =
proc getStrLit(m: BModule, s: string): Rope = proc getStrLit(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq") discard cgsym(m, "TGenericSeq")
result = "TMP" & rope(backendId()) result = getTempName(m)
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), rope(len(s))]) [result, makeCString(s), rope(len(s))])
@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of nkNilLit: of nkNilLit:
let t = skipTypes(ty, abstractVarRange) let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure: if t.kind == tyProc and t.callConv == ccClosure:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = "TMP" & rope(id) result = p.module.tmpBase & rope(id)
if id == gBackendId: if id == p.module.labels:
# not found in cache: # not found in cache:
inc(gBackendId) inc(p.module.labels)
addf(p.module.s[cfsData], addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result]) [getTypeDesc(p.module, t), result])
@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if n.strVal.isNil: if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", []) result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
elif skipTypes(ty, abstractVarRange).kind == tyString: elif skipTypes(ty, abstractVarRange).kind == tyString:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
if id == gBackendId: if id == p.module.labels:
# string literal not found in the cache: # string literal not found in the cache:
result = ropecg(p.module, "((#NimStringDesc*) &$1)", result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, n.strVal)]) [getStrLit(p.module, n.strVal)])
else: else:
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)]) result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
[p.module.tmpBase, rope(id)])
else: else:
result = makeCString(n.strVal) result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope =
var size = int(getSize(n.typ)) var size = int(getSize(n.typ))
toBitSet(n, cs) toBitSet(n, cs)
if size > 8: if size > 8:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = "TMP" & rope(id) result = p.module.tmpBase & rope(id)
if id == gBackendId: if id == p.module.labels:
# not found in cache: # not found in cache:
inc(gBackendId) inc(p.module.labels)
addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else: else:
@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
var size = getSize(t) var size = getSize(t)
let storage = if size < platform.intSize: rope("NI") let storage = if size < platform.intSize: rope("NI")
else: getTypeDesc(p.module, t) else: getTypeDesc(p.module, t)
result = getTempName() result = getTempName(p.module)
linefmt(p, cpsLocals, "$1 $2;$n", storage, result) linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b)) lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum}: 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)", # EqPtr
"($1 <= $2)", # LePtr "($1 <= $2)", # LePtr
"($1 < $2)", # LtPtr "($1 < $2)", # LtPtr
"($1 == $2)", # EqCString
"($1 != $2)"] # Xor "($1 != $2)"] # Xor
var var
a, b: TLoc a, b: TLoc
@ -612,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
assert(e.sons[2].typ != nil) assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if a.t.callConv == ccClosure: if a.t.skipTypes(abstractInst).callConv == ccClosure:
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
"($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)]) "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
else: else:
@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
#if e[0].kind != nkBracketExpr: #if e[0].kind != nkBracketExpr:
# message(e.info, warnUser, "CAME HERE " & renderTree(e)) # message(e.info, warnUser, "CAME HERE " & renderTree(e))
expr(p, e.sons[0], d) expr(p, e.sons[0], d)
if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
d.s = OnHeap
else: else:
var a: TLoc var a: TLoc
let typ = skipTypes(e.sons[0].typ, abstractInst) 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) v.r.add(d.loc.r)
genInExprAux(p, it, u, v, test) genInExprAux(p, it, u, v, test)
let id = nodeTableTestOrSet(p.module.dataCache, let id = nodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId) newStrNode(nkStrLit, field.name.s), p.module.labels)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s) let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
else: "TMP" & rope(id) else: p.module.tmpBase & rope(id)
if op.magic == mNot: if op.magic == mNot:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n", "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@ -1141,7 +1143,35 @@ proc genNewSeq(p: BProc, e: PNode) =
genNewSeqAux(p, a, b.rdLoc) genNewSeqAux(p, a, b.rdLoc)
gcUsage(e) 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) = proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
if handleConstExpr(p, e, d): return
#echo rendertree e, " ", e.isDeepConstExpr
var tmp: TLoc var tmp: TLoc
var t = e.typ.skipTypes(abstractInst) var t = e.typ.skipTypes(abstractInst)
getTemp(p, t, tmp) 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 # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first: # have to call it here first:
let ti = genTypeInfo(p.module, dest) 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): tfObjHasKids notin dest.flags):
result = "$1.m_type == $2" % [a, ti] result = "$1.m_type == $2" % [a, ti]
else: 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) putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.s)
of tyEnum, tyOrdinal: of tyEnum, tyOrdinal:
putIntoDest(p, d, e.typ, 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) rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyString: of tyString:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s) 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, putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprAny($1, $2)", [ ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.s) rdLoc(a), genTypeInfo(p.module, t)]), a.s)
of tyEmpty: of tyEmpty, tyVoid:
localError(e.info, "'repr' doesn't support 'void' type") localError(e.info, "'repr' doesn't support 'void' type")
else: else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", 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) [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
proc genCast(p: BProc, e: PNode, d: var TLoc) = proc genCast(p: BProc, e: PNode, d: var TLoc) =
const floatTypes = {tyFloat..tyFloat128} const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject,
tyArray, tyArrayConstr}
let let
destt = skipTypes(e.typ, abstractRange) destt = skipTypes(e.typ, abstractRange)
srct = skipTypes(e.sons[1].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. # 'cast' and some float type involved? --> use a union.
inc(p.labels) inc(p.labels)
var lbl = p.labels.rope var lbl = p.labels.rope
@ -1712,6 +1743,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNew: genNew(p, e) of mNew: genNew(p, e)
of mNewFinalize: genNewFinalize(p, e) of mNewFinalize: genNewFinalize(p, e)
of mNewSeq: genNewSeq(p, e) of mNewSeq: genNewSeq(p, e)
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
of mSizeOf: of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc}) let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) 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, x, a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
genDeepCopy(p, a, b) genDeepCopy(p, a, b)
of mDotDot: genCall(p, e, d) of mDotDot, mEqCString: genCall(p, e, d)
else: internalError(e.info, "genMagicExpr: " & $op) 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) = proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
# example: { a..b, c, d, e, f..g } # example: { a..b, c, d, e, f..g }
# we have to emit an expression of the form: # we have to emit an expression of the form:
@ -1856,6 +1872,12 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[1], b) initLocExpr(p, n.sons[1], b)
if n.sons[0].skipConv.kind == nkClosure: if n.sons[0].skipConv.kind == nkClosure:
internalError(n.info, "closure to closure created") internalError(n.info, "closure to closure created")
# 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) getTemp(p, n.typ, tmp)
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n", linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
tmp.rdLoc, a.rdLoc, b.rdLoc) tmp.rdLoc, a.rdLoc, b.rdLoc)
@ -1947,12 +1969,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ) var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
var tmp = "TMP" & rope(id) let tmp = p.module.tmpBase & rope(id)
if id == gBackendId: if id == p.module.labels:
# expression not found in the cache: # expression not found in the cache:
inc(gBackendId) inc(p.module.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, 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) fillLoc(d, locData, t, tmp, OnStatic)
else: else:
putDataIntoDest(p, d, t, tmp) 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) = proc expr(p: BProc, n: PNode, d: var TLoc) =
case n.kind 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) internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
of skConst: of skConst:
if sfFakeConst in sym.flags: if isSimpleConst(sym.typ):
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
putLocIntoDest(p, d, sym.loc)
elif isSimpleConst(sym.typ):
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic) putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic)
else: else:
genComplexConst(p, sym, d) genComplexConst(p, sym, d)
@ -2160,7 +2183,8 @@ proc genConstSimpleList(p: BProc, n: PNode): Rope =
result = rope("{") result = rope("{")
for i in countup(ord(n.kind == nkObjConstr), length - 2): for i in countup(ord(n.kind == nkObjConstr), length - 2):
addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) 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", []) addf(result, "}$n", [])
proc genConstSeq(p: BProc, n: PNode, t: PType): Rope = 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("}")
data.add("}") data.add("}")
inc(gBackendId) result = getTempName(p.module)
result = "CNSTSEQ" & gBackendId.rope
appcg(p.module, cfsData, appcg(p.module, cfsData,
"NIM_CONST struct {$n" & "NIM_CONST struct {$n" &

View file

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

View file

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

View file

@ -18,7 +18,7 @@ proc emulatedThreadVars(): bool =
proc accessThreadLocalVar(p: BProc, s: PSym) = proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed: if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true p.threadVarAccessed = true
p.module.usesThreadVars = true incl p.module.flags, usesThreadVars
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", []) addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
add(p.procSec(cpsInit), add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n")) 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]) addf(m.s[cfsVars], " $1;$n", [s.loc.r])
proc generateThreadLocalStorage(m: BModule) = 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) for t in items(nimtvDeps): discard getTypeDesc(m, t)
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv]) 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 = proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)
result = getGlobalTempName() result = getTempName(m)
case reason case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)
var sLoc = s.loc.r var sLoc = s.loc.r
result = getGlobalTempName() result = getTempName(m)
if sfThread in s.flags and emulatedThreadVars(): if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s) accessThreadLocalVar(p, s)
@ -143,7 +143,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p c.p = p
let header = "N_NIMCALL(void, $1)()" % [result] let header = "N_NIMCALL(void, $1)(void)" % [result]
genTraverseProc(c, sLoc, s.loc.t) genTraverseProc(c, sLoc, s.loc.t)
let generatedProc = "$1 {$n$2$3$4}$n" % let generatedProc = "$1 {$n$2$3$4}$n" %

View file

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

View file

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

View file

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

View file

@ -92,19 +92,23 @@ type
gcFrameType*: Rope # the struct {} we put the GC markers into gcFrameType*: Rope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType] 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 TCGen = object of TPassContext # represents a C source file
s*: TCFileSections # sections of the C file
flags*: set[Codegenflag]
module*: PSym module*: PSym
filename*: string 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, cfilename*: string # filename of the module (including path,
# without extension) # without extension)
tmpBase*: Rope # base for temp identifier generation
typeCache*: TIdTable # cache the generated types typeCache*: TIdTable # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types forwTypeCache*: TIdTable # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file declaredThings*: IntSet # things we have declared in this .c file

View file

@ -63,21 +63,27 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
while true: while true:
aa = skipTypes(aa, {tyGenericInst}) aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {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 aa = aa.lastSon
bb = bb.lastSon bb = bb.lastSon
else: else:
break break
if sameType(aa, bb): 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: elif aa.kind == tyObject and bb.kind == tyObject:
let diff = inheritanceDiff(bb, aa) let diff = inheritanceDiff(bb, aa)
if diff < 0: if diff < 0:
if result != Invalid: result = Yes if result != Invalid:
result = Yes
else:
return No
elif diff != high(int): elif diff != high(int):
result = Invalid result = Invalid
else: else:
return No return No
else:
return No
proc attachDispatcher(s: PSym, dispatcher: PNode) = proc attachDispatcher(s: PSym, dispatcher: PNode) =
var L = s.ast.len-1 var L = s.ast.len-1
@ -181,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
var aa = skipTypes(a.typ.sons[col], skipPtrs) var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs) var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb) var d = inheritanceDiff(aa, bb)
if (d != high(int)): if (d != high(int)) and d != 0:
return d return d
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = 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 # We do this here before the 'import' statement so 'defined' does not get
# confused with 'TGCMode.gcGenerational' etc. # 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. # Helper to build boot constants, for debugging you can 'echo' the else part.
const name = if expr: " " & userString else: "" const name = if expr: " " & userString else: ""
@ -158,7 +158,7 @@ var
enableNotes: TNoteKinds enableNotes: TNoteKinds
disableNotes: TNoteKinds disableNotes: TNoteKinds
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string) = info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off" var id = "" # arg = "X]:on|off"
var i = 0 var i = 0
@ -181,10 +181,13 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
case whichKeyword(substr(arg, i)) case whichKeyword(substr(arg, i))
of wOn: of wOn:
incl(gNotes, n) incl(gNotes, n)
incl(gMainPackageNotes, n)
incl(enableNotes, n) incl(enableNotes, n)
of wOff: of wOff:
excl(gNotes, n) excl(gNotes, n)
excl(gMainPackageNotes, n)
incl(disableNotes, n) incl(disableNotes, n)
excl(ForeignPackageNotes, n)
else: localError(info, errOnOrOffExpectedButXFound, arg) else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processCompile(filename: string) = proc processCompile(filename: string) =
@ -213,6 +216,16 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
of "size": result = contains(gOptions, optOptimizeSize) of "size": result = contains(gOptions, optOptimizeSize)
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) 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) else: invalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool = proc testCompileOption*(switch: string, info: TLineInfo): bool =
@ -253,20 +266,18 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "experimental": result = gExperimentalMode of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info) else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false, proc processPath(path: string, info: TLineInfo,
cfginfo = unknownLineInfo()): string = notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or let p = if notRelativeToProj or os.isAbsolute(path) or
'$' in path or path[0] == '.': '$' in path or path[0] == '.':
path path
else: else:
options.gProjectPath / path options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(), try:
"nim", getPrefixDir(), result = pathSubs(p, info.toFullPath().splitFile().dir)
"lib", libpath, except ValueError:
"home", removeTrailingDirSep(os.getHomeDir()), localError(info, "invalid path: " & p)
"config", cfginfo.toFullPath().splitFile().dir, result = p
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
proc trackDirty(arg: string, info: TLineInfo) = proc trackDirty(arg: string, info: TLineInfo) =
var a = arg.split(',') var a = arg.split(',')
@ -307,19 +318,22 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
case switch.normalize case switch.normalize
of "path", "p": of "path", "p":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
addPath(processPath(arg, cfginfo=info), info) addPath(processPath(arg, info), info)
of "nimblepath", "babelpath": of "nimblepath", "babelpath":
# keep the old name for compat # keep the old name for compat
if pass in {passCmd2, passPP} and not options.gNoNimblePath: if pass in {passCmd2, passPP} and not options.gNoNimblePath:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
let path = processPath(arg, notRelativeToProj=true) let path = processPath(arg, info, notRelativeToProj=true)
nimblePath(path, info) nimblePath(path, info)
of "nonimblepath", "nobabelpath": of "nonimblepath", "nobabelpath":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
options.gNoNimblePath = true options.gNoNimblePath = true
options.lazyPaths.head = nil
options.lazyPaths.tail = nil
options.lazyPaths.counter = 0
of "excludepath": of "excludepath":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
let path = processPath(arg) let path = processPath(arg, info)
lists.excludePath(options.searchPaths, path) lists.excludePath(options.searchPaths, path)
lists.excludePath(options.lazyPaths, path) lists.excludePath(options.lazyPaths, path)
if (len(path) > 0) and (path[len(path) - 1] == DirSep): 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) lists.excludePath(options.lazyPaths, strippedPath)
of "nimcache": of "nimcache":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg, true) options.nimcacheDir = processPath(arg, info, true)
of "out", "o": of "out", "o":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.outFile = arg options.outFile = arg
@ -339,6 +353,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
discard "allow for backwards compatibility, but don't do anything" discard "allow for backwards compatibility, but don't do anything"
of "define", "d": of "define", "d":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if {':', '='} in arg:
splitSwitch(arg, key, val, pass, info)
defineSymbol(key, val)
else:
defineSymbol(arg) defineSymbol(arg)
of "undef", "u": of "undef", "u":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
@ -407,6 +425,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints() if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, 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 "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
of "debugger": of "debugger":
case arg.normalize case arg.normalize
@ -493,13 +512,13 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg) if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes": of "cincludes":
expectArg(switch, arg, pass, info) 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": of "clibdir":
expectArg(switch, arg, pass, info) 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": of "clib":
expectArg(switch, arg, pass, info) 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": of "header":
headerFile = arg headerFile = arg
incl(gGlobalOptions, optGenIndex) incl(gGlobalOptions, optGenIndex)
@ -540,6 +559,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
gNotes = NotesVerbosity[gVerbosity] gNotes = NotesVerbosity[gVerbosity]
incl(gNotes, enableNotes) incl(gNotes, enableNotes)
excl(gNotes, disableNotes) excl(gNotes, disableNotes)
gMainPackageNotes = gNotes
of "parallelbuild": of "parallelbuild":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
gNumberOfProcessors = parseInt(arg) gNumberOfProcessors = parseInt(arg)
@ -572,7 +592,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info) of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
of "lib": of "lib":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
libpath = processPath(arg, notRelativeToProj=true) libpath = processPath(arg, info, notRelativeToProj=true)
of "putenv": of "putenv":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info) splitSwitch(arg, key, val, pass, info)

View file

@ -19,8 +19,8 @@ var gSymbols: StringTableRef
const const
catNone = "false" catNone = "false"
proc defineSymbol*(symbol: string) = proc defineSymbol*(symbol: string, value: string = "true") =
gSymbols[symbol] = "true" gSymbols[symbol] = value
proc undefSymbol*(symbol: string) = proc undefSymbol*(symbol: string) =
gSymbols[symbol] = catNone gSymbols[symbol] = catNone
@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool =
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s) 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 = iterator definedSymbolNames*: string =
for key, val in pairs(gSymbols): for key, val in pairs(gSymbols):
if val != catNone: yield key if val != catNone: yield key
@ -93,3 +98,4 @@ proc initDefines*() =
defineSymbol("nimtypedescfixed") defineSymbol("nimtypedescfixed")
defineSymbol("nimKnowsNimvm") defineSymbol("nimKnowsNimvm")
defineSymbol("nimArrIdx") 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 import
ast, strutils, strtabs, options, msgs, os, ropes, idents, ast, strutils, strtabs, options, msgs, os, ropes, idents,
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
importer, sempass2, json, xmltree, cgi, typesrenderer importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
type type
TSections = array[TSymKind, Rope] TSections = array[TSymKind, Rope]
@ -25,9 +25,32 @@ type
indexValFilename: string indexValFilename: string
analytics: string # Google Analytics javascript, "" if doesn't exist analytics: string # Google Analytics javascript, "" if doesn't exist
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
jArray: JsonNode
types: TStrTable
PDoc* = ref TDocumentor ## Alias to type less. 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, proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} = msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind: # translate msg kind:
@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.seenSymbols = newStringTable(modeCaseInsensitive) result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100 result.id = 100
result.jArray = newJArray()
initStrTable result.types
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) = proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: addf(dest, xml, args) if gCmd != cmdRst2tex: addf(dest, xml, args)
@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
result = esc(d.target, "`") result = esc(d.target, "`")
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter)) for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
result.add esc(d.target, "`") result.add esc(d.target, "`")
of nkOpenSymChoice, nkClosedSymChoice:
result = getName(d, n[0], splitAfter)
else: else:
internalError(n.info, "getName()") internalError(n.info, "getName()")
result = "" 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 = proc getRstName(n: PNode): PRstNode =
case n.kind case n.kind
of nkPostfix: result = getRstName(n.sons[1]) of nkPostfix: result = getRstName(n.sons[1])
@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
of nkAccQuoted: of nkAccQuoted:
result = getRstName(n.sons[0]) result = getRstName(n.sons[0])
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text) for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
of nkOpenSymChoice, nkClosedSymChoice:
result = getRstName(n[0])
else: else:
internalError(n.info, "getRstName()") internalError(n.info, "getRstName()")
result = nil result = nil
@ -380,13 +424,27 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid: of tkSpaces, tkInvalid:
add(result, literal) 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, of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, tkBracketDotLe, tkBracketDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon, tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))]) [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) inc(d.id)
let let
plainNameRope = rope(xmltree.escape(plainName.strip)) plainNameRope = rope(xmltree.escape(plainName.strip))
@ -402,12 +460,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
var seeSrcRope: Rope = nil var seeSrcRope: Rope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc") let docItemSeeSrc = getConfigVar("doc.item.seesrc")
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0: if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
# XXX toFilename doesn't really work. We need to ensure that this keeps let path = n.info.toFilename.extractFilename.rope
# returning a relative path.
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl, 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, dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
["path", "line", "url"], [n.info.toFilename.rope, ["path", "line", "url"], [path,
rope($n.info.line), urlRope])]) rope($n.info.line), urlRope])])
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), 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, setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary)) 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 if not isVisible(nameNode): return
var var
name = getName(d, nameNode) name = getName(d, nameNode)
@ -441,8 +500,8 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) 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 != "": if comm != nil and comm != "":
result["description"] = %comm result["description"] = %comm
if r.buf != nil: if r.buf != nil:
@ -492,46 +551,45 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: discard 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 case n.kind
of nkCommentStmt: of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"): if n.comment != nil and startsWith(n.comment, "##"):
let stripped = n.comment.substr(2).strip let stripped = n.comment.substr(2).strip
result = %{ "comment": %stripped } d.add %{ "comment": %stripped, "line": %n.info.line,
"col": %n.info.col }
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skProc) d.add genJsonItem(d, n, n.sons[namePos], skProc)
of nkMethodDef: of nkMethodDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skMethod) d.add genJsonItem(d, n, n.sons[namePos], skMethod)
of nkIteratorDef: of nkIteratorDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
result = genJSONItem(d, n, n.sons[namePos], skIterator) d.add genJsonItem(d, n, n.sons[namePos], skIterator)
of nkMacroDef: of nkMacroDef:
result = genJSONItem(d, n, n.sons[namePos], skMacro) d.add genJsonItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: of nkTemplateDef:
result = genJSONItem(d, n, n.sons[namePos], skTemplate) d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: of nkConverterDef:
when useEffectSystem: documentRaises(n) 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: of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt: if n.sons[i].kind != nkCommentStmt:
# order is always 'type var let const': # 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))) succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList: of nkStmtList:
result = if jArray != nil: jArray else: newJArray()
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var r = generateJson(d, n.sons[i], result) generateJson(d, n.sons[i])
if r != nil:
result.add(r)
of nkWhenStmt: of nkWhenStmt:
# generate documentation for the first branch only: # generate documentation for the first branch only:
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil: if not checkForFalse(n.sons[0].sons[0]):
discard generateJson(d, lastSon(n.sons[0]), jArray) generateJson(d, lastSon(n.sons[0]))
else: discard else: discard
proc genSection(d: PDoc, kind: TSymKind) = proc genSection(d: PDoc, kind: TSymKind) =
@ -593,12 +651,36 @@ proc generateIndex*(d: PDoc) =
writeIndexFile(d[], splitFile(options.outFile).dir / writeIndexFile(d[], splitFile(options.outFile).dir /
splitFile(d.filename).name & IndexExt) 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) = proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d) var content = genOutFile(d)
if optStdout in gGlobalOptions: if optStdout in gGlobalOptions:
writeRope(stdout, content) writeRope(stdout, content)
else: 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*() = proc commandDoc*() =
var ast = parseFile(gProjectMainIdx) var ast = parseFile(gProjectMainIdx)
@ -629,18 +711,19 @@ proc commandRst2TeX*() =
splitter = "\\-" splitter = "\\-"
commandRstAux(gProjectFull, TexExt) commandRstAux(gProjectFull, TexExt)
proc commandJSON*() = proc commandJson*() =
var ast = parseFile(gProjectMainIdx) var ast = parseFile(gProjectMainIdx)
if ast == nil: return if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars) var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true d.hasToc = true
var json = generateJson(d, ast) generateJson(d, ast)
var content = rope(pretty(json)) let json = d.jArray
let content = rope(pretty(json))
if optStdout in gGlobalOptions: if optStdout in gGlobalOptions:
writeRope(stdout, content) writeRope(stdout, content)
else: else:
echo getOutFile(gProjectFull, JsonExt) #echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc commandBuildIndex*() = proc commandBuildIndex*() =

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,7 +11,7 @@
import idents, strutils, os, options import idents, strutils, os, options
var gFrontEndId, gBackendId*: int var gFrontEndId*: int
const const
debugIds* = false debugIds* = false
@ -30,10 +30,6 @@ proc getID*(): int {.inline.} =
result = gFrontEndId result = gFrontEndId
inc(gFrontEndId) inc(gFrontEndId)
proc backendId*(): int {.inline.} =
result = gBackendId
inc(gBackendId)
proc setId*(id: int) {.inline.} = proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1) gFrontEndId = max(gFrontEndId, id + 1)
@ -49,7 +45,6 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) = proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite) var f = open(project.toGid, fmWrite)
f.writeLine($gFrontEndId) f.writeLine($gFrontEndId)
f.writeLine($gBackendId)
f.close() f.close()
proc loadMaxIds*(project: string) = proc loadMaxIds*(project: string) =
@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) =
if f.readLine(line): if f.readLine(line):
var backEndId = parseInt(line) var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId) gFrontEndId = max(gFrontEndId, frontEndId)
gBackendId = max(gBackendId, backEndId)
f.close() 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 # The proc won't perform any checks that the path is actually valid
case n.kind case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit: 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: of nkIdent:
result = n.ident.s result = n.ident.s
of nkSym: of nkSym:
@ -172,7 +176,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[i]) var m = myImportModule(c, n.sons[i])
if m != nil: if m != nil:
# ``addDecl`` needs to be done before ``importAllSymbols``! # ``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) importAllSymbolsExcept(c, m, emptySet)
#importForwarded(c, m.ast, emptySet) #importForwarded(c, m.ast, emptySet)
@ -182,7 +186,7 @@ proc evalFrom(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0])
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) 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): for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind != nkNilLit: if n.sons[i].kind != nkNilLit:
importSymbol(c, n.sons[i], m) importSymbol(c, n.sons[i], m)
@ -193,7 +197,7 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0])
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) 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() var exceptSet = initIntSet()
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let ident = lookups.considerQuotedIdent(n.sons[i]) let ident = lookups.considerQuotedIdent(n.sons[i])

View file

@ -8,7 +8,7 @@ Platforms: """
windows: i386;amd64 windows: i386;amd64
linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64 linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
macosx: i386;amd64;powerpc64 macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64 freebsd: i386;amd64
netbsd: i386;amd64 netbsd: i386;amd64
openbsd: i386;amd64 openbsd: i386;amd64
@ -48,8 +48,8 @@ Start: "doc/overview.html"
[Other] [Other]
Files: "readme.txt;install.txt;contributors.txt;copying.txt" Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "makefile" Files: "makefile"
Files: "*.ini"
Files: "koch.nim" Files: "koch.nim"
Files: "install_nimble.nims"
Files: "icons/nim.ico" Files: "icons/nim.ico"
Files: "icons/nim.rc" Files: "icons/nim.rc"
@ -60,176 +60,26 @@ Files: "icons/koch.rc"
Files: "icons/koch.res" Files: "icons/koch.res"
Files: "icons/koch_icon.o" Files: "icons/koch_icon.o"
Files: "compiler/readme.txt" Files: "compiler"
Files: "compiler/installer.ini" Files: "doc"
Files: "compiler/*.cfg" Files: "tools"
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: "web/website.ini" Files: "web/website.ini"
Files: "web/ticker.html"
Files: "web/*.nim" Files: "web/*.nim"
Files: "web/*.txt" Files: "web/*.rst"
Files: "web/*.csv"
Files: "web/news/*.rst"
Files: "bin/nimblepkg/*.nim" Files: "bin/nimblepkg/*.nim"
Files: "bin/nimblepkg/*.cfg" Files: "bin/nimblepkg/*.cfg"
[Lib] [Lib]
Files: "lib/nimbase.h" Files: "lib"
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"
[Other] [Other]
Files: "examples/*.nim" Files: "examples"
Files: "examples/c++iface/*.nim" #Files: "dist/nimble"
Files: "examples/objciface/*.nim"
Files: "examples/cross_calculator/"
Files: "examples/*.html" Files: "tests"
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"
[Windows] [Windows]
Files: "bin/nim.exe" 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"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"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"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 ; for now only NSIS supports optional downloads
[UnixBin] [UnixBin]
@ -279,3 +129,7 @@ buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)" pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nim Compiler" shortDesc: "The Nim Compiler"
licenses: "bin/nim,MIT;lib/*,MIT;" 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. # This is the JavaScript code generator.
# Soon also a PHP code generator. ;-) # Also a PHP code generator. ;-)
discard """ discard """
The JS code generator contains only 2 tricks: The JS code generator contains only 2 tricks:
@ -48,6 +48,7 @@ type
etyNull, # null type etyNull, # null type
etyProc, # proc type etyProc, # proc type
etyBool, # bool type etyBool, # bool type
etySeq, # Nim seq or string type
etyInt, # JavaScript's int etyInt, # JavaScript's int
etyFloat, # JavaScript's float etyFloat, # JavaScript's float
etyString, # JavaScript's string etyString, # JavaScript's string
@ -71,7 +72,7 @@ type
isLoop: bool # whether it's a 'block' or 'while' isLoop: bool # whether it's a 'block' or 'while'
TGlobals = object TGlobals = object
typeInfo, code: Rope typeInfo, constants, code: Rope
forwarded: seq[PSym] forwarded: seq[PSym]
generatedSyms: IntSet generatedSyms: IntSet
typeInfoGenerated: IntSet typeInfoGenerated: IntSet
@ -94,7 +95,7 @@ type
up: PProc # up the call chain; required for closure support up: PProc # up the call chain; required for closure support
declaredGlobals: IntSet declaredGlobals: IntSet
template `|`(a, b: expr): expr {.immediate, dirty.} = template `|`(a, b: untyped): untyped {.dirty.} =
(if p.target == targetJS: a else: b) (if p.target == targetJS: a else: b)
proc newGlobals(): PGlobals = proc newGlobals(): PGlobals =
@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
of tyBool: result = etyBool of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table 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, of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
tyVarargs: tyVarargs:
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
result = etyNone result = etyNone
of tyStatic:
if t.n != nil: result = mapType(lastSon t)
else: result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString
@ -237,7 +241,7 @@ proc useMagic(p: PProc, name: string) =
internalAssert s.kind in {skProc, skMethod, skConverter} internalAssert s.kind in {skProc, skMethod, skConverter}
if not p.g.generatedSyms.containsOrIncl(s.id): if not p.g.generatedSyms.containsOrIncl(s.id):
let code = genProc(p, s) let code = genProc(p, s)
add(p.g.code, code) add(p.g.constants, code)
else: else:
# we used to exclude the system module from this check, but for DLL # we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so # 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)"], # EqUntracedRef
["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr ["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
["", "", "($1 < $2)", "($1 < $2)"], # LtPtr ["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 != $2)", "($1 != $2)"], # Xor ["", "", "($1 != $2)", "($1 != $2)"], # Xor
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
["", "", "($1 == $2)", "($1 == $2)"], # EqProc ["", "", "($1 == $2)", "($1 == $2)"], # EqProc
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI ["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64 ["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]) addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
return 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: if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
gen(p, x.sons[0], a) gen(p, x.sons[0], a)
@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
gen(p, y, b) 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 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: of etyObject:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) 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] r.res = "nimAt($1, $2)" % [r.address, r.res]
elif ty.kind in {tyString, tyCString}: elif ty.kind in {tyString, tyCString}:
# XXX this needs to be more like substr($1,$2) # 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: else:
r.res = "$1[$2]" % [r.address, r.res] r.res = "$1[$2]" % [r.address, r.res]
else: else:
@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv: of nkObjDownConv:
gen(p, n.sons[0], r) 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) else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
proc thisParam(p: PProc; typ: PType): PType = 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) genArgNoParam(p, it, r)
else: else:
genArg(p, it, paramType.sym, r) genArg(p, it, paramType.sym, r)
inc generated
proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
r: var TCompRes) = r: var TCompRes) =
var i = 0 var i = 0
var j = 1 var j = 1
r.kind = resExpr
while i < pat.len: while i < pat.len:
case pat[i] case pat[i]
of '@': of '@':
@ -1233,16 +1252,27 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
genOtherArg(p, n, j, typ, generated, r) genOtherArg(p, n, j, typ, generated, r)
inc j inc j
inc i inc i
of '\31':
# unit separator
add(r.res, "#")
inc i
of '\29':
# group separator
add(r.res, "@")
inc i
else: else:
let start = i let start = i
while i < pat.len: while i < pat.len:
if pat[i] notin {'@', '#'}: inc(i) if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
add(r.res, substr(pat, start, i - 1)) add(r.res, substr(pat, start, i - 1))
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
# don't call '$' here for efficiency: # don't call '$' here for efficiency:
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 let pat = n.sons[0].sym.loc.r.data
internalAssert pat != nil internalAssert pat != nil
if pat.contains({'#', '(', '@'}): if pat.contains({'#', '(', '@'}):
@ -1250,6 +1280,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
genPatternCall(p, n, pat, typ, r) genPatternCall(p, n, pat, typ, r)
return return
if n.len != 1:
gen(p, n.sons[1], r) gen(p, n.sons[1], r)
if r.typ == etyBaseIndex: if r.typ == etyBaseIndex:
if r.address == nil: if r.address == nil:
@ -1266,7 +1297,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
genArgs(p, n, r, 2) genArgs(p, n, r, 2)
proc genCall(p: PProc, n: PNode, r: var TCompRes) = 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) genInfixCall(p, n, r)
return return
if p.target == targetPHP: if p.target == targetPHP:
@ -1400,6 +1431,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect) result = putToSeq("null", indirect)
of tySequence, tyString, tyCString, tyPointer, tyProc: of tySequence, tyString, tyCString, tyPointer, tyProc:
result = putToSeq("null", indirect) result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
result = createVar(p, lastSon t, indirect)
else:
internalError("createVar: " & $t.kind)
result = nil
else: else:
internalError("createVar: " & $t.kind) internalError("createVar: " & $t.kind)
result = nil result = nil
@ -1409,13 +1446,16 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
a: TCompRes a: TCompRes
s: Rope s: Rope
if n.kind == nkEmpty: if n.kind == nkEmpty:
let mname = mangleName(v, p.target)
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n", 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: else:
discard mangleName(v, p.target) discard mangleName(v, p.target)
gen(p, n, a) gen(p, n, a)
case mapType(p, v.typ) case mapType(p, v.typ)
of etyObject: of etyObject, etySeq:
if needsNoCopy(p, n): if needsNoCopy(p, n):
s = a.res s = a.res
else: else:
@ -1458,7 +1498,7 @@ proc genConstant(p: PProc, c: PSym) =
p.body = nil p.body = nil
#genLineDir(p, c.ast) #genLineDir(p, c.ast)
genVarInit(p, c, c.ast) genVarInit(p, c, c.ast)
add(p.g.code, p.body) add(p.g.constants, p.body)
p.body = oldBody p.body = oldBody
proc genNew(p: PProc, n: PNode) = proc genNew(p: PProc, n: PNode) =
@ -1554,8 +1594,16 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
of tyEnum, tyOrdinal: of tyEnum, tyOrdinal:
gen(p, n.sons[1], r) gen(p, n.sons[1], r)
useMagic(p, "cstrToNimstr") 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.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: else:
# XXX: # XXX:
internalError(n.info, "genRepr: Not implemented") internalError(n.info, "genRepr: Not implemented")
@ -1645,6 +1693,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r) of mOrd: genOrd(p, n, r)
of mLengthStr: of mLengthStr:
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)" | unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
"strlen($1)") "strlen($1)")
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)") of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)")
@ -1672,8 +1723,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
else: else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($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 mSetLengthStr:
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "") 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 mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)") of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($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 mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true") of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]") 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 mNewSeq: genNewSeq(p, n)
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
of mOf: genOf(p, n, r) of mOf: genOf(p, n, r)
of mReset: genReset(p, n) of mReset: genReset(p, n)
of mEcho: genEcho(p, n, r) of mEcho: genEcho(p, n, r)
@ -1877,9 +1952,13 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
let header = generateHeader(p, prc.typ) let header = generateHeader(p, prc.typ)
if prc.typ.sons[0] != nil and sfPure notin prc.flags: if prc.typ.sons[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast.sons[resultPos].sym resultSym = prc.ast.sons[resultPos].sym
let mname = mangleName(resultSym, p.target)
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [ resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
mangleName(resultSym, p.target), mname,
createVar(p, resultSym.typ, isIndirect(resultSym))] 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) gen(p, prc.ast.sons[resultPos], a)
if mapType(p, resultSym.typ) == etyBaseIndex: if mapType(p, resultSym.typ) == etyBaseIndex:
returnStmt = "return [$#, $#];$n" % [a.address, a.res] 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): if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
genMagic(p, n, r) genMagic(p, n, r)
elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and 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) genInfixCall(p, n, r)
else: else:
genCall(p, n, r) genCall(p, n, r)
@ -2131,7 +2210,7 @@ proc wholeCode*(m: BModule): Rope =
var p = newProc(globals, m, nil, m.module.options) var p = newProc(globals, m, nil, m.module.options)
attachProc(p, prc) attachProc(p, prc)
result = globals.typeInfo & globals.code result = globals.typeInfo & globals.constants & globals.code
proc getClassName(t: PType): Rope = proc getClassName(t: PType): Rope =
var s = t.sym var s = t.sym

View file

@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
of tyEnum: genEnumInfo(p, t, result) of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result) of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(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 & ')') 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") #localError(n.info, "internal error: closure to closure created")
# now we know better, so patch it: # now we know better, so patch it:
n.sons[0] = x.sons[0] n.sons[0] = x.sons[0]
n.sons[1] = x.sons[1]
of nkLambdaKinds, nkIteratorDef: of nkLambdaKinds, nkIteratorDef:
if n.typ != nil and n[namePos].kind == nkSym: if n.typ != nil and n[namePos].kind == nkSym:
let m = newSymNode(n[namePos].sym) let m = newSymNode(n[namePos].sym)
m.typ = n.typ m.typ = n.typ
result = liftCapturedVars(m, owner, d, c) 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: else:
if owner.isIterator: if owner.isIterator:
if n.kind == nkYieldStmt: if n.kind == nkYieldStmt:

View file

@ -138,6 +138,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
proc isKeyword*(kind: TTokType): bool = proc isKeyword*(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
proc isNimIdentifier*(s: string): bool = proc isNimIdentifier*(s: string): bool =
if s[0] in SymStartChars: if s[0] in SymStartChars:
var i = 1 var i = 1
@ -589,11 +591,28 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
of '\\': of '\\':
add(tok.literal, '\\') add(tok.literal, '\\')
inc(L.bufpos) inc(L.bufpos)
of 'x', 'X': of 'x', 'X', 'u', 'U':
var tp = L.buf[L.bufpos]
inc(L.bufpos) inc(L.bufpos)
var xi = 0 var xi = 0
handleHexChar(L, xi) handleHexChar(L, xi)
handleHexChar(L, xi) handleHexChar(L, 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)) add(tok.literal, chr(xi))
of '0'..'9': of '0'..'9':
if matchTwoChars(L, '0', {'0'..'9'}): if matchTwoChars(L, '0', {'0'..'9'}):
@ -716,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
if c == '\226' and if c == '\226' and
buf[pos+1] == '\128' and buf[pos+1] == '\128' and
buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode 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, "–") lexMessage(L, errInvalidToken, "–")
break break
inc(pos, magicIdentSeparatorRuneByteWidth) inc(pos, magicIdentSeparatorRuneByteWidth)
@ -728,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
h = h !& ord(c) h = h !& ord(c)
inc(pos) inc(pos)
of '_': of '_':
if buf[pos+1] notin SymChars: if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
lexMessage(L, errInvalidToken, "_") lexMessage(L, errInvalidToken, "_")
break break
inc(pos) inc(pos)
@ -811,10 +831,6 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
break break
dec nesting dec nesting
inc pos inc pos
of '\t':
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
inc(pos)
if isDoc: tok.literal.add '\t'
of CR, LF: of CR, LF:
pos = handleCRLF(L, pos) pos = handleCRLF(L, pos)
buf = L.buf buf = L.buf
@ -877,10 +893,10 @@ proc scanComment(L: var TLexer, tok: var TToken) =
inc(indent) inc(indent)
when defined(nimfix): when defined(nimfix):
template doContinue(): expr = template doContinue(): untyped =
buf[pos] == '#' and (col == indent or lastBackslash > 0) buf[pos] == '#' and (col == indent or lastBackslash > 0)
else: else:
template doContinue(): expr = template doContinue(): untyped =
buf[pos] == '#' and buf[pos+1] == '#' buf[pos] == '#' and buf[pos+1] == '#'
if doContinue(): if doContinue():
tok.literal.add "\n" tok.literal.add "\n"
@ -926,9 +942,9 @@ proc skip(L: var TLexer, tok: var TToken) =
break break
tok.strongSpaceA = 0 tok.strongSpaceA = 0
when defined(nimfix): when defined(nimfix):
template doBreak(): expr = buf[pos] > ' ' template doBreak(): untyped = buf[pos] > ' '
else: else:
template doBreak(): expr = template doBreak(): untyped =
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#') buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
if doBreak(): if doBreak():
tok.indent = indent tok.indent = indent
@ -1041,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
inc(L.bufpos) inc(L.bufpos)
of '_': of '_':
inc(L.bufpos) 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.tokType = tkSymbol
tok.ident = getIdent("_") tok.ident = getIdent("_")
else: else:
@ -1062,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
tok.tokType = tkCharLit tok.tokType = tkCharLit
of '0'..'9': of '0'..'9':
getNumber(L, tok) getNumber(L, tok)
let c = L.buf[L.bufpos]
if c in SymChars+{'_'}:
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
else: else:
if c in OpChars: if c in OpChars:
getOperator(L, tok) 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 = proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope): for scope in walkScopes(c.currentScope):
result = strTableGet(scope.symbols, s) var ti: TIdentIter
if result != nil and result.kind in filter: return var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter: return candidate
candidate = nextIdentIter(ti, scope.symbols)
result = nil result = nil
proc errorSym*(c: PContext, n: PNode): PSym = proc errorSym*(c: PContext, n: PNode): PSym =
@ -153,7 +156,8 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}: if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
# XXX: implicit type params are currently skTypes # XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well. # 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)) message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols) s = nextIter(it, scope.symbols)
@ -161,6 +165,10 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive: if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s) 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) = proc addDecl*(c: PContext, sym: PSym) =
if not c.currentScope.addUniqueSym(sym): if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s) 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)) of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
else: result = x else: result = x
template fixSpelling(n: PNode; ident: PIdent; op: expr) = template fixSpelling(n: PNode; ident: PIdent; op: untyped) =
let alt = ident.altSpelling let alt = ident.altSpelling
result = op(c, alt).skipAlias(n) result = op(c, alt).skipAlias(n)
if result != nil: if result != nil:
prettybase.replaceDeprecated(n.info, ident, alt) prettybase.replaceDeprecated(n.info, ident, alt)
return result return result
else: 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 = proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil. # 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") internalError(n.info, "lookUp")
return return
if contains(c.ambiguousSymbols, result.id): if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s) errorUseQualifier(c, n.info, result)
if result.kind == skStub: loadStub(result) if result.kind == skStub: loadStub(result)
type type
TLookupFlag* = enum 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 case n.kind
of nkIdent, nkAccQuoted: of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(n) var ident = considerQuotedIdent(n)
if checkModule in flags:
result = searchInScopes(c, ident).skipAlias(n) result = searchInScopes(c, ident).skipAlias(n)
else:
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
if result == nil and checkUndeclared in flags: if result == nil and checkUndeclared in flags:
fixSpelling(n, ident, searchInScopes) fixSpelling(n, ident, searchInScopes)
localError(n.info, errUndeclaredIdentifier, ident.s) localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n) result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and elif checkAmbiguity in flags and result != nil and
contains(c.ambiguousSymbols, result.id): contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, ident.s) errorUseQualifier(c, n.info, result)
of nkSym: of nkSym:
result = n.sym result = n.sym
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id): 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: of nkDotExpr:
result = nil 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: if m != nil and m.kind == skModule:
var ident: PIdent = nil var ident: PIdent = nil
if n.sons[1].kind == nkIdent: if n.sons[1].kind == nkIdent:
@ -313,7 +338,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimDone o.mode = oimDone
of nkDotExpr: of nkDotExpr:
o.mode = oimOtherModule 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: if o.m != nil and o.m.kind == skModule:
var ident: PIdent = nil var ident: PIdent = nil
if n.sons[1].kind == nkIdent: 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) let slice = newNodeI(nkCall, n.info, 4)
slice.typ = n.typ slice.typ = n.typ
slice.sons[0] = newSymNode(createMagic("slice", mSlice)) slice.sons[0] = newSymNode(createMagic("slice", mSlice))
slice.sons[0].typ = getSysType(tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info) var fieldB = newSym(skField, tmpName, objType.owner, n.info)
fieldB.typ = getSysType(tyInt) fieldB.typ = getSysType(tyInt)
objType.addField(fieldB) objType.addField(fieldB)
@ -577,6 +578,8 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
var fn = n.sons[0] var fn = n.sons[0]
# templates and macros are in fact valid here due to the nature of # templates and macros are in fact valid here due to the nature of
# the transformation: # 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, if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skMethod, skConverter}): skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj # 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 = proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter var ti: TIdentIter
let id = getIdent(name) let id = getIdent(name)
result = initIdentIter(ti, systemModule.tab, id) var r = initIdentIter(ti, systemModule.tab, id)
while result != nil: while r != nil:
if result.kind == skStub: loadStub(result) if r.kind == skStub: loadStub(r)
if result.magic == m: return result if r.magic == m:
result = nextIdentIter(ti, systemModule.tab) # 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) rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info) result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule) result.typ = newType(tyError, systemModule)

View file

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

View file

@ -29,12 +29,16 @@ var
gMemCacheData*: seq[TModuleInMemory] = @[] gMemCacheData*: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs ## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing ## 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 = proc getModule*(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len: if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx] result = gCompiledModules[fileIdx]
template hash(x: PSym): expr = template hash(x: PSym): untyped =
gMemCacheData[x.position].hash gMemCacheData[x.position].hash
proc hashChanged(fileIdx: int32): bool = proc hashChanged(fileIdx: int32): bool =
@ -45,7 +49,7 @@ proc hashChanged(fileIdx: int32): bool =
else: hashNotChanged else: hashNotChanged
# echo "TESTING Hash: ", fileIdx.toFilename, " ", result # echo "TESTING Hash: ", fileIdx.toFilename, " ", result
case gMemCacheData[fileIdx].hashStatus: case gMemCacheData[fileIdx].hashStatus
of hashHasChanged: of hashHasChanged:
result = true result = true
of hashNotChanged: of hashNotChanged:
@ -90,6 +94,7 @@ proc resetAllModules* =
if gCompiledModules[i] != nil: if gCompiledModules[i] != nil:
resetModule(i.int32) resetModule(i.int32)
resetPackageCache() resetPackageCache()
initStrTable(packageSyms)
# for m in cgenModules(): echo "CGEN MODULE FOUND" # for m in cgenModules(): echo "CGEN MODULE FOUND"
proc resetAllModulesHard* = proc resetAllModulesHard* =
@ -97,6 +102,7 @@ proc resetAllModulesHard* =
gCompiledModules.setLen 0 gCompiledModules.setLen 0
gMemCacheData.setLen 0 gMemCacheData.setLen 0
magicsys.resetSysTypes() magicsys.resetSysTypes()
initStrTable(packageSyms)
# XXX # XXX
#gOwners = @[] #gOwners = @[]
@ -105,12 +111,16 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
resetModule(fileIdx) resetModule(fileIdx)
return Yes return Yes
if gFuzzyGraphChecking:
if gMemCacheData[fileIdx].needsRecompile != Maybe: if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile 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 if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
hashChanged(fileIdx): markDirty()
markDirty
if gMemCacheData[fileIdx].deps != nil: if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing gMemCacheData[fileIdx].needsRecompile = Probing
@ -118,7 +128,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
let d = checkDepMem(dep) let d = checkDepMem(dep)
if d in {Yes, Recompiled}: if d in {Yes, Recompiled}:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty markDirty()
gMemCacheData[fileIdx].needsRecompile = No gMemCacheData[fileIdx].needsRecompile = No
return No return No
@ -135,8 +145,16 @@ proc newModule(fileIdx: int32): PSym =
rawMessage(errInvalidModuleName, result.name.s) rawMessage(errInvalidModuleName, result.name.s)
result.info = newLineInfo(fileIdx, 1, 1) result.info = newLineInfo(fileIdx, 1, 1)
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil, let pack = getIdent(getPackageName(filename))
result.info) 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 result.position = fileIdx
growCache gMemCacheData, fileIdx growCache gMemCacheData, fileIdx
@ -146,6 +164,11 @@ proc newModule(fileIdx: int32): PSym =
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
initStrTable(result.tab) initStrTable(result.tab)
strTableAdd(result.tab, result) # a module knows itself 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 = proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx) result = getModule(fileIdx)
@ -156,6 +179,9 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
#var rd = handleSymbolFile(result) #var rd = handleSymbolFile(result)
var rd: PRodReader var rd: PRodReader
result.flags = result.flags + flags result.flags = result.flags + flags
if sfMainModule in result.flags:
gMainPackageId = result.owner.id
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result) rd = handleSymbolFile(result)
if result.id < 0: if result.id < 0:
@ -181,8 +207,11 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
# this is called by the semantic checking phase # this is called by the semantic checking phase
result = compileModule(fileIdx, {}) result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags: #if sfSystemModule in result.flags:
localError(result.info, errAttemptToRedefine, result.name.s) # 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.} = proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx) result = syntaxes.parseFile(fileIdx)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -67,6 +67,8 @@ type # please make sure we have under 32 options
optIdeDebug # idetools: debug mode optIdeDebug # idetools: debug mode
optIdeTerse # idetools: use terse descriptions optIdeTerse # idetools: use terse descriptions
optNoCppExceptions # use C exception handling even with CPP optNoCppExceptions # use C exception handling even with CPP
optExcessiveStackTrace # fully qualified module filenames
TGlobalOptions* = set[TGlobalOption] TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nim's commands TCommands* = enum # Nim's commands
# **keep binary compatible** # **keep binary compatible**
@ -127,10 +129,10 @@ var
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
template compilationCachePresent*: expr = template compilationCachePresent*: untyped =
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
template optPreserveOrigSource*: expr = template optPreserveOrigSource*: untyped =
optEmbedOrigSrc in gGlobalOptions optEmbedOrigSrc in gGlobalOptions
const const
@ -149,6 +151,7 @@ const
var var
gConfigVars* = newStringTable(modeStyleInsensitive) gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive) gDllOverrides = newStringTable(modeCaseInsensitive)
gModuleOverrides* = newStringTable(modeStyleInsensitive)
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
libpath* = "" libpath* = ""
gProjectName* = "" # holds a name like 'nim' gProjectName* = "" # holds a name like 'nim'
@ -209,9 +212,7 @@ proc setDefaultLibpath*() =
# Special rule to support other tools (nimble) which import the compiler # Special rule to support other tools (nimble) which import the compiler
# modules and make use of them. # modules and make use of them.
let realNimPath = # Make sure we expand the symlink let realNimPath = findExe("nim")
if symlinkExists(findExe("nim")): expandSymlink(findExe("nim"))
else: findExe("nim")
# Find out if $nim/../../lib/system.nim exists. # Find out if $nim/../../lib/system.nim exists.
let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib" let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
if not fileExists(libpath / "system.nim") and if not fileExists(libpath / "system.nim") and
@ -219,7 +220,7 @@ proc setDefaultLibpath*() =
libpath = parentNimLibPath libpath = parentNimLibPath
proc canonicalizePath*(path: string): string = proc canonicalizePath*(path: string): string =
when not FileSystemCaseSensitive: result = path.expandFilename.toLower when not FileSystemCaseSensitive: result = path.expandFilename.toLowerAscii
else: result = path.expandFilename else: result = path.expandFilename
proc shortenDir*(dir: string): string = proc shortenDir*(dir: string): string =
@ -238,57 +239,26 @@ proc removeTrailingDirSep*(path: string): string =
else: else:
result = path result = path
include packagehandling
proc getNimcacheDir*: string = proc getNimcacheDir*: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir genSubDir
template newPackageCache(): expr =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache() proc pathSubs*(p, config: string): string =
let home = removeTrailingDirSep(os.getHomeDir())
proc resetPackageCache*() = packageCache = newPackageCache() result = unixToNativePath(p % [
"nim", getPrefixDir(),
iterator myParentDirs(p: string): string = "lib", libpath,
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug... "home", home,
var current = p "config", config,
while true: "projectname", options.gProjectName,
current = current.parentDir "projectpath", options.gProjectPath,
if current.len == 0: break "projectdir", options.gProjectPath,
yield current "nimcache", getNimcacheDir()])
if '~' in result:
proc getPackageName*(path: string): string = result = result.replace("~", home)
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 toGeneratedFile*(path, ext: string): string = proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" ## 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) it = PStrEntry(it.next)
result = "" 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.} = proc findFile*(f: string): string {.procvar.} =
if f.isAbsolute: if f.isAbsolute:
result = if f.existsFile: f else: "" result = if f.existsFile: f else: ""
else: else:
result = f.rawFindFile result = f.rawFindFile
if result.len == 0: if result.len == 0:
result = f.toLower.rawFindFile result = f.toLowerAscii.rawFindFile
if result.len == 0: if result.len == 0:
result = f.rawFindFile2 result = f.rawFindFile2
if result.len == 0: if result.len == 0:
result = f.toLower.rawFindFile2 result = f.toLowerAscii.rawFindFile2
patchModule()
proc findModule*(modulename, currentModule: string): string = proc findModule*(modulename, currentModule: string): string =
# returns path to module # returns path to module
@ -386,6 +364,7 @@ proc findModule*(modulename, currentModule: string): string =
result = currentPath / m result = currentPath / m
if not existsFile(result): if not existsFile(result):
result = findFile(m) result = findFile(m)
patchModule()
proc libCandidates*(s: string, dest: var seq[string]) = proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(') var le = strutils.find(s, '(')
@ -426,10 +405,10 @@ proc binaryStrSearch*(x: openArray[string], y: string): int =
return mid return mid
result = - 1 result = - 1
template nimdbg*: expr = c.module.fileIdx == gProjectMainIdx template nimdbg*: untyped = c.module.fileIdx == gProjectMainIdx
template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx template cnimdbg*: untyped = p.module.module.fileIdx == gProjectMainIdx
template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx template pnimdbg*: untyped = p.lex.fileIdx == gProjectMainIdx
template lnimdbg*: expr = L.fileIdx == gProjectMainIdx template lnimdbg*: untyped = L.fileIdx == gProjectMainIdx
proc parseIdeCmd*(s: string): IdeCmd = proc parseIdeCmd*(s: string): IdeCmd =
case s: 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` ## Produce and emit a parser message to output about the token `tok`
parMessage(p, msg, prettyTok(tok)) parMessage(p, msg, prettyTok(tok))
template withInd(p: expr, body: stmt) {.immediate.} = template withInd(p, body: untyped) =
let oldInd = p.currInd let oldInd = p.currInd
p.currInd = p.tok.indent p.currInd = p.tok.indent
body body
@ -202,7 +202,7 @@ proc isRightAssociative(tok: TToken): bool {.inline.} =
proc getPrecedence(tok: TToken, strongSpaces: bool): int = proc getPrecedence(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token. ## 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) x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType case tok.tokType
@ -214,7 +214,7 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
if L > 1 and tok.ident.s[L-1] == '>' and if L > 1 and tok.ident.s[L-1] == '>' and
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1) 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 result = if tok.ident.s[L-1] == '=': 1 else: value
case relevantChar case relevantChar
@ -326,6 +326,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
getTok(p) getTok(p)
else: else:
parMessage(p, errIdentifierExpected, p.tok) parMessage(p, errIdentifierExpected, p.tok)
break
eat(p, tkAccent) eat(p, tkAccent)
else: else:
if allowNil and p.tok.tokType == tkNil: if allowNil and p.tok.tokType == tkNil:
@ -685,11 +686,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| | '{' optInd indexExprList optPar '}' #| | '{' optInd indexExprList optPar '}'
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
result = r 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 while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent): (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
case p.tok.tokType case p.tok.tokType
of tkParLe: of tkParLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break somePar()
result = namedParams(p, result, nkCall, tkParRi) result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr: if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr result.kind = nkObjConstr
@ -704,10 +713,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = dotExpr(p, result) result = dotExpr(p, result)
result = parseGStrLit(p, result) result = parseGStrLit(p, result)
of tkBracketLe: of tkBracketLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break somePar()
result = namedParams(p, result, nkBracketExpr, tkBracketRi) result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe: of tkCurlyLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break somePar()
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
if p.inPragma == 0: if p.inPragma == 0:
@ -963,8 +972,9 @@ proc parseDoBlock(p: var TParser): PNode =
proc parseDoBlocks(p: var TParser, call: PNode) = proc parseDoBlocks(p: var TParser, call: PNode) =
#| doBlocks = doBlock ^* IND{=} #| doBlocks = doBlock ^* IND{=}
if p.tok.tokType == tkDo: if p.tok.tokType == tkDo:
addSon(call, parseDoBlock(p)) #withInd(p):
while sameInd(p) and p.tok.tokType == tkDo: # addSon(call, parseDoBlock(p))
while sameOrNoInd(p) and p.tok.tokType == tkDo:
addSon(call, parseDoBlock(p)) addSon(call, parseDoBlock(p))
proc parseProcExpr(p: var TParser, isExpr: bool): PNode = 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 # system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally: # messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing) incl(msgs.gNotes, hintProcessing)
message(n.info, hintProcessing, $idgen.gBackendId) message(n.info, hintProcessing, $idgen.gFrontendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) 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) result = matchNodeKinds(p.constraint, n)
if not result: return if not result: return
if isNil(n.typ): if isNil(n.typ):
result = p.typ.kind in {tyEmpty, tyStmt} result = p.typ.kind in {tyVoid, tyStmt}
else: else:
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ) 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) result = bindOrCheck(c, p.sons[2].sym, arglist)
proc matches(c: PPatternContext, p, n: PNode): bool = proc matches(c: PPatternContext, p, n: PNode): bool =
# hidden conversions (?) let n = skipHidden(n)
if nfNoRewrite in n.flags: if nfNoRewrite in n.flags:
result = false result = false
elif isPatternParam(c, p): elif isPatternParam(c, p):

View file

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

View file

@ -63,11 +63,12 @@ const
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, 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 letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wLocks, wTags, wGcSafe} wThread, wRaises, wLocks, wTags, wGcSafe}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation # implementation
@ -89,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
else: else:
invalidPragma(it) invalidPragma(it)
proc setExternName(s: PSym, extname: string) = 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) 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: if gCmd == cmdPretty and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}' # note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName) s.loc.flags.incl(lfFullExternalName)
proc makeExternImport(s: PSym, extname: string) = proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname) setExternName(s, extname, info)
incl(s.flags, sfImportc) incl(s.flags, sfImportc)
excl(s.flags, sfForward) 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) = proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname) setExternName(s, extname, info)
# XXX to fix make it work with nimrtl.
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
# validateExternCName(s, info)
incl(s.flags, sfExportc) incl(s.flags, sfExportc)
proc processImportCompilerProc(s: PSym, extname: string) = proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname) setExternName(s, extname, info)
incl(s.flags, sfImportc) incl(s.flags, sfImportc)
excl(s.flags, sfForward) excl(s.flags, sfForward)
incl(s.loc.flags, lfImportCompilerProc) incl(s.loc.flags, lfImportCompilerProc)
proc processImportCpp(s: PSym, extname: string) = proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname) setExternName(s, extname, info)
incl(s.flags, sfImportc) incl(s.flags, sfImportc)
incl(s.flags, sfInfixCall) incl(s.flags, sfInfixCall)
excl(s.flags, sfForward) excl(s.flags, sfForward)
@ -133,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
incl(m.flags, sfCompileToCpp) incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true extccomp.gMixedMode = true
proc processImportObjC(s: PSym, extname: string) = proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
setExternName(s, extname) setExternName(s, extname, info)
incl(s.flags, sfImportc) incl(s.flags, sfImportc)
incl(s.flags, sfNamedParamCall) incl(s.flags, sfNamedParamCall)
excl(s.flags, sfForward) excl(s.flags, sfForward)
@ -256,8 +252,9 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
proc processDynLib(c: PContext, n: PNode, sym: PSym) = proc processDynLib(c: PContext, n: PNode, sym: PSym) =
if (sym == nil) or (sym.kind == skModule): if (sym == nil) or (sym.kind == skModule):
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic, let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
expectDynlibNode(c, n)) if not lib.isOverriden:
POptionEntry(c.optionStack.tail).dynlib = lib
else: else:
if n.kind == nkExprColonExpr: if n.kind == nkExprColonExpr:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n)) 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) = proc processNote(c: PContext, n: PNode) =
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
(n.sons[0].kind == nkBracketExpr) 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[1].kind == nkIdent) and
(n.sons[0].sons[0].kind == nkIdent): (n.sons[0].sons[0].kind == nkIdent):
#and (n.sons[1].kind == nkIdent): #and (n.sons[1].kind == nkIdent):
@ -391,21 +389,25 @@ type
TLinkFeature = enum TLinkFeature = enum
linkNormal, linkSys linkNormal, linkSys
proc processCompile(c: PContext, n: PNode) = proc relativeFile(c: PContext; n: PNode; ext=""): string =
var s = expectStrLit(c, n) var s = expectStrLit(c, n)
var found = findFile(s) if ext.len > 0 and splitFile(s).ext == "":
if found == "": found = s s = addFileExt(s, ext)
var trunc = changeFileExt(found, "") result = parentDir(n.info.toFullPath) / s
if not isAbsolute(found): if not fileExists(result):
found = parentDir(n.info.toFullPath) / found 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.addExternalFileToCompile(found)
extccomp.addFileToLink(completeCFilePath(trunc, false)) extccomp.addFileToLink(completeCFilePath(trunc, false))
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
var f = expectStrLit(c, n) let found = relativeFile(c, n, CC[cCompiler].objExt)
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
var found = findFile(f)
if found == "": found = f # use the default
case feature case feature
of linkNormal: extccomp.addFileToLink(found) of linkNormal: extccomp.addFileToLink(found)
of linkSys: of linkSys:
@ -564,7 +566,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
localError(pragma.info, "list of key:value pairs expected"); return localError(pragma.info, "list of key:value pairs expected"); return
for n in pragma: for n in pragma:
if n.kind in {nkExprColonExpr, nkExprEqExpr}: 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 src = considerQuotedIdent(n[0])
let alias = newSym(skAlias, src, dest, n[0].info) let alias = newSym(skAlias, src, dest, n[0].info)
incl(alias.flags, sfExported) incl(alias.flags, sfExported)
@ -589,7 +591,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
# and perform the lookup on demand instead. # and perform the lookup on demand instead.
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info) result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
else: else:
result = qualifiedLookUp(c, n) result = qualifiedLookUp(c, n, {checkUndeclared})
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
validPragmas: TSpecialWords): bool = validPragmas: TSpecialWords): bool =
@ -616,20 +618,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wExportc: of wExportc:
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
incl(sym.flags, sfUsed) # avoid wrong hints 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: of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
of wExtern: setExternName(sym, expectStrLit(c, it)) of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
of wImmediate: 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) else: invalidPragma(it)
of wDirty: of wDirty:
if sym.kind == skTemplate: incl(sym.flags, sfDirty) if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(it) else: invalidPragma(it)
of wImportCpp: of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, "$1")) processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
of wImportObjC: of wImportObjC:
processImportObjC(sym, getOptionalStr(c, it, "$1")) processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
of wAlign: of wAlign:
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)
var align = expectIntLit(c, it) var align = expectIntLit(c, it)
@ -894,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wBase: of wBase:
noVal(it) noVal(it)
sym.flags.incl sfBase sym.flags.incl sfBase
of wIntDefine:
sym.magic = mIntDefine
of wStrDefine:
sym.magic = mStrDefine
else: invalidPragma(it) else: invalidPragma(it)
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) = proc gproc(g: var TSrcGen, n: PNode) =
var c: TContext var c: TContext
if n.sons[namePos].kind == nkSym: 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: else:
gsub(g, n.sons[namePos]) gsub(g, n.sons[namePos])
@ -712,6 +715,10 @@ proc gproc(g: var TSrcGen, n: PNode) =
gpattern(g, n.sons[patternPos]) gpattern(g, n.sons[patternPos])
let oldCheckAnon = g.checkAnon let oldCheckAnon = g.checkAnon
g.checkAnon = true g.checkAnon = true
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]) gsub(g, n.sons[genericParamsPos])
g.checkAnon = oldCheckAnon g.checkAnon = oldCheckAnon
gsub(g, n.sons[paramsPos]) gsub(g, n.sons[paramsPos])
@ -794,7 +801,8 @@ proc gident(g: var TSrcGen, n: PNode) =
else: else:
t = tkOpr t = tkOpr
put(g, t, s) 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) = proc doParamsAux(g: var TSrcGen, params: PNode) =
if params.len > 1: if params.len > 1:
@ -802,7 +810,7 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
gsemicolon(g, params, 1) gsemicolon(g, params, 1)
put(g, tkParRi, ")") put(g, tkParRi, ")")
if params.sons[0].kind != nkEmpty: if params.len > 0 and params.sons[0].kind != nkEmpty:
putWithSpace(g, tkOpr, "->") putWithSpace(g, tkOpr, "->")
gsub(g, params.sons[0]) gsub(g, params.sons[0])

View file

@ -64,7 +64,7 @@ const
const const
vintDelta = 5 vintDelta = 5
template encodeIntImpl(self: expr) = template encodeIntImpl(self) =
var d: char var d: char
var v = x var v = x
var rem = v mod 190 var rem = v mod 190

View file

@ -13,10 +13,10 @@
import import
ast, modules, passes, passaux, condsyms, ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times, osproc os, times, osproc, wordrecg, strtabs
# we support 'cmpIgnoreStyle' natively for efficiency: # we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle from strutils import cmpIgnoreStyle, contains
proc listDirs(a: VmArgs, filter: set[PathComponent]) = proc listDirs(a: VmArgs, filter: set[PathComponent]) =
let dir = getString(a, 0) let dir = getString(a, 0)
@ -116,12 +116,27 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
setResult(a, options.command) setResult(a, options.command)
cbconf switch: cbconf switch:
processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo()) 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; freshDefines=true) =
proc runNimScript*(scriptName: string) =
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule
passes.gImportModule = importModule passes.gImportModule = importModule
initDefines() if freshDefines: initDefines()
defineSymbol("nimscript") defineSymbol("nimscript")
defineSymbol("nimconfig") 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 # templates perform some quick check whether the cursor is actually in
# the generic or template. # the generic or template.
when defined(nimsuggest): when defined(nimsuggest):
assert gCmd == cmdIdeTools if gCmd == cmdIdeTools and requiresCheck:
if requiresCheck:
#if optIdeDebug in gGlobalOptions: #if optIdeDebug in gGlobalOptions:
# echo "passing to safeSemExpr: ", renderTree(n) # echo "passing to safeSemExpr: ", renderTree(n)
discard safeSemExpr(c, 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 = proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
if arg.typ.isNil: if arg.typ.isNil:
localError(arg.info, errExprXHasNoType, 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) result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = 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 # like newSymS, but considers gensym'ed symbols
if n.kind == nkSym: if n.kind == nkSym:
@ -316,6 +306,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
include hlo, seminst, semcall 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, proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
## Semantically check the output of a macro. ## 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) c.friendModules.add(s.owner.getModule)
result = n result = n
excl(n.flags, nfSem)
#resetSemFlag n
if s.typ.sons[0] == nil: if s.typ.sons[0] == nil:
result = semStmt(c, result) result = semStmt(c, result)
else: else:
@ -363,7 +362,6 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil: #if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic) # c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, n, nOrig, sym) result = evalMacroCall(c.module, n, nOrig, sym)
if efNoSemCheck notin flags: if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags) result = semAfterMacroCall(c, result, sym, flags)
@ -419,17 +417,42 @@ proc myOpen(module: PSym): PPassContext =
c.importTable.addSym(module) # a module knows itself c.importTable.addSym(module) # a module knows itself
if sfSystemModule in module.flags: if sfSystemModule in module.flags:
magicsys.systemModule = module # set global variable! magicsys.systemModule = module # set global variable!
else:
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
c.topLevelScope = openScope(c) 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 result = c
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module) result = myOpen(module)
for m in items(rd.methods): methodDef(m, true) 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 = 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: if sfNoForward in c.module.flags:
result = semAllTypeSections(c, n) result = semAllTypeSections(c, n)
else: 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) = proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind case t.kind
of tyNone, tyEmpty: discard of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
tyPtr, tyString, tyRef: tyPtr, tyString, tyRef:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)

View file

@ -53,7 +53,18 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
if symx.kind in filter: if symx.kind in filter:
syms.add((symx, o.lastOverloadScope)) syms.add((symx, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol) symx = nextOverloadIter(o, c, headSymbol)
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 if syms.len == 0: return
else:
return
var z: TCandidate var z: TCandidate
initCandidate(c, best, syms[0][0], initialBinding, symScope) initCandidate(c, best, syms[0][0], initialBinding, symScope)
@ -69,7 +80,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# gDebug = true # gDebug = true
matches(c, n, orig, z) matches(c, n, orig, z)
if errors != nil: if errors != nil:
errors.safeAdd(sym) errors.safeAdd((sym, int z.mutabilityProblem))
if z.errors != nil: if z.errors != nil:
for err in z.errors: for err in z.errors:
errors.add(err) errors.add(err)
@ -111,7 +122,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
let proto = describeArgs(c, n, 1, preferName) let proto = describeArgs(c, n, 1, preferName)
var prefer = preferName var prefer = preferName
for err in errors: for err, mut in items(errors):
var errProto = "" var errProto = ""
let n = err.typ.n let n = err.typ.n
for i in countup(1, n.len - 1): for i in countup(1, n.len - 1):
@ -123,14 +134,21 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
if errProto == proto: if errProto == proto:
prefer = preferModuleInfo prefer = preferModuleInfo
break break
# now use the information stored in 'prefer' to produce a nice error message: # now use the information stored in 'prefer' to produce a nice error message:
var result = msgKindToString(errTypeMismatch) var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1, prefer)) add(result, describeArgs(c, n, 1, prefer))
add(result, ')') add(result, ')')
var candidates = "" var candidates = ""
for err in errors: 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, err.getProcHeader(prefer))
add(candidates, "\n") 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 != "": if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions: if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
@ -138,6 +156,20 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
else: else:
localError(n.info, errGenerated, result) 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, proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds; filter: TSymKinds;
errors: var CandidateErrors): TCandidate = errors: var CandidateErrors): TCandidate =
@ -154,8 +186,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
template pickBest(headSymbol) = template pickBest(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding, pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors) filter, result, alt, errors)
pickBest(f) pickBest(f)
let overloadsState = result.state let overloadsState = result.state
@ -226,7 +256,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
#notFoundError(c, n, errors) #notFoundError(c, n, errors)
return return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
not sameMethodDispatcher(result.calleeSym, alt.calleeSym): not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
internalAssert result.state == csMatch internalAssert result.state == csMatch
@ -295,8 +324,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
var finalCallee = x.calleeSym var finalCallee = x.calleeSym
markUsed(n.sons[0].info, finalCallee) markUsed(n.sons[0].info, finalCallee)
styleCheckUse(n.sons[0].info, finalCallee) styleCheckUse(n.sons[0].info, finalCallee)
if finalCallee.ast == nil: assert finalCallee.ast != nil
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if x.hasFauxMatch: if x.hasFauxMatch:
result = x.call result = x.call
result.sons[0] = newSymNode(finalCallee, result.sons[0].info) result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
@ -361,7 +389,14 @@ proc explicitGenericInstError(n: PNode): PNode =
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var m: TCandidate 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) var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(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) "; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n return n
result = explicitGenericSym(c, n, s) result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(n)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}: elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters. # choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch. # 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 # it suffices that the candidate has the proper number of generic
# type parameters: # type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1: 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: # get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice: if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0] result = result[0]
# candidateCount != 1: return explicitGenericInstError(n) elif result.len == 0: result = explicitGenericInstError(n)
else: else:
result = explicitGenericInstError(n) result = explicitGenericInstError(n)

View file

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

View file

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

View file

@ -15,7 +15,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s) styleCheckUse(n.info, s)
pushInfoContext(n.info) 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) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
popInfoContext() popInfoContext()
@ -24,16 +24,15 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semOperand(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 # same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand}) 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: # do not produce another redundant error message:
#raiseRecoverableError("") #raiseRecoverableError("")
result = errorNode(c, n) # result = errorNode(c, n)
if result.typ != nil: if result.typ != nil:
# XXX tyGenericInst here? # XXX tyGenericInst here?
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}: elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyEmpty, c) result.typ = newTypeS(tyVoid, c)
result.typ.flags.incl tfVoid
else: else:
localError(n.info, errExprXHasNoType, localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
@ -51,7 +50,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
result.typ = errorType(c) result.typ = errorType(c)
else: else:
# XXX tyGenericInst here?
if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
semDestructorCheck(c, result, flags) semDestructorCheck(c, result, flags)
@ -74,6 +72,10 @@ proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast) result = copyTree(s.ast)
if result.isNil:
localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
result = newSymNode(s)
else:
result.typ = s.typ result.typ = s.typ
result.info = n.info result.info = n.info
@ -83,8 +85,9 @@ type
convNotNeedeed, convNotNeedeed,
convNotLegal convNotLegal
proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus = proc checkConversionBetweenObjects(castDest, src: PType; pointers: int): TConvStatus =
return if inheritanceDiff(castDest, src) == high(int): let diff = inheritanceDiff(castDest, src)
return if diff == high(int) or (pointers > 1 and diff != 0):
convNotLegal convNotLegal
else: else:
convOK convOK
@ -101,13 +104,15 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
return return
var d = skipTypes(castDest, abstractVar) var d = skipTypes(castDest, abstractVar)
var s = skipTypes(src, abstractVar-{tyTypeDesc}) var s = skipTypes(src, abstractVar-{tyTypeDesc})
var pointers = 0
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind): while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
d = d.lastSon d = d.lastSon
s = s.lastSon s = s.lastSon
inc pointers
if d == nil: if d == nil:
result = convNotLegal result = convNotLegal
elif d.kind == tyObject and s.kind == tyObject: 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 elif (skipTypes(castDest, abstractVarRange).kind in IntegralTypes) and
(skipTypes(src, abstractVarRange-{tyTypeDesc}).kind in IntegralTypes): (skipTypes(src, abstractVarRange-{tyTypeDesc}).kind in IntegralTypes):
# accept conversion between integral types # accept conversion between integral types
@ -186,15 +191,15 @@ proc semConv(c: PContext, n: PNode): PNode =
case status case status
of convOK: of convOK:
# handle SomeProcType(SomeGenericProc) # 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: if op.kind == nkSym and op.sym.isGenericRoutine:
result.sons[1] = fitNode(c, result.typ, result.sons[1]) 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: of convNotNeedeed:
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
of convNotLegal: of convNotLegal:
result = fitNode(c, result.typ, result.sons[1])
if result == nil:
localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)% localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
[op.typ.typeToString, result.typ.typeToString]) [op.typ.typeToString, result.typ.typeToString])
else: else:
@ -206,7 +211,7 @@ proc semConv(c: PContext, n: PNode): PNode =
styleCheckUse(n.info, it.sym) styleCheckUse(n.info, it.sym)
markIndirect(c, it.sym) markIndirect(c, it.sym)
return it 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 = proc semCast(c: PContext, n: PNode): PNode =
## Semantically analyze a casting ("cast[type](param)") ## Semantically analyze a casting ("cast[type](param)")
@ -594,6 +599,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
result = n result = n
if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
var callee = n.sons[0].sym 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: # constant folding that is necessary for correctness of semantic pass:
if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil: 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) initCandidate(c, result, t)
matches(c, n, nOrig, result) 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 = proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil result = nil
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var prc = n.sons[0] var prc = n.sons[0]
if n.sons[0].kind == nkDotExpr: if n.sons[0].kind == nkDotExpr:
checkSonsLen(n.sons[0], 2) checkSonsLen(n.sons[0], 2)
n.sons[0] = semFieldAccess(c, n.sons[0]) let n0 = semFieldAccess(c, n.sons[0])
if n.sons[0].kind == nkDotCall: if n0.kind == nkDotCall:
# it is a static call! # it is a static call!
result = n.sons[0] result = n0
result.kind = nkCall result.kind = nkCall
result.flags.incl nfExplicitCall result.flags.incl nfExplicitCall
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i]) for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
return semExpr(c, result, flags) return semExpr(c, result, flags)
else: else:
n.sons[0] = semExpr(c, n.sons[0]) n.sons[0] = n0
else:
n.sons[0] = semExpr(c, n.sons[0], {efInCall})
let t = n.sons[0].typ let t = n.sons[0].typ
if t != nil and t.kind == tyVar: if t != nil and t.kind == tyVar:
n.sons[0] = newDeref(n.sons[0]) 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 let nOrig = n.copyTree
semOpAux(c, n) semOpAux(c, n)
var t: PType = nil 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)
else: else:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags) of skMacro:
of skTemplate: result = semTemplateExpr(c, n, s, flags) 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: of skParam:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(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 = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ) result.typ = makeTypeDesc(c, s.typ)
of skField: of skField:
if c.p != nil and c.p.selfSym != nil: var p = c.p
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) 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}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
var check: PNode = nil var check: PNode = nil
if ty.kind == tyObject: if ty.kind == tyObject:
@ -1025,7 +1083,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
markUsed(n.info, f) markUsed(n.info, f)
styleCheckUse(n.info, f) styleCheckUse(n.info, f)
result = newNodeIT(nkDotExpr, n.info, f.typ) 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 result.add newSymNode(f) # we now have the correct field
if check != nil: if check != nil:
check.sons[0] = result check.sons[0] = result
@ -1051,7 +1109,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# here at all! # here at all!
#if isSymChoice(n.sons[1]): return #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 != nil:
if s.kind in OverloadableSyms: if s.kind in OverloadableSyms:
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
@ -1186,7 +1244,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0]) result.add(x[0])
return return
checkMinSonsLen(n, 2) 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}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
case arr.kind case arr.kind
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
@ -1229,14 +1289,32 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
let s = if n.sons[0].kind == nkSym: n.sons[0].sym let s = if n.sons[0].kind == nkSym: n.sons[0].sym
elif n[0].kind in nkSymChoices: n.sons[0][0].sym elif n[0].kind in nkSymChoices: n.sons[0][0].sym
else: nil else: nil
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: if s != nil:
case s.kind
of skProc, skMethod, skConverter, skIterator:
# type parameters: partial generic specialization # type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s) result = explicitGenericInstantiation(c, n, s)
elif s != nil and s.kind == skType: 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) result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
else: else:
c.p.bracketExpr = n.sons[0] c.p.bracketExpr = n.sons[0]
else:
c.p.bracketExpr = n.sons[0]
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
let oldBracketExpr = c.p.bracketExpr let oldBracketExpr = c.p.bracketExpr
@ -1287,7 +1365,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
n.sons[1] = takeImplicitAddr(c, ri) n.sons[1] = takeImplicitAddr(c, ri)
x.typ.flags.incl tfVarIsPtr x.typ.flags.incl tfVarIsPtr
template resultTypeIsInferrable(typ: PType): expr = template resultTypeIsInferrable(typ: PType): untyped =
typ.isMetaType and typ.kind != tyTypeDesc typ.isMetaType and typ.kind != tyTypeDesc
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = 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) # --> `[]=`(a, i, x)
let oldBracketExpr = c.p.bracketExpr let oldBracketExpr = c.p.bracketExpr
a = semSubscript(c, a, {efLValue}) a = semSubscript(c, a, {efLValue})
if a == nil and mode != noOverloadedSubscript: if a == nil:
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
add(result, n[1]) add(result, n[1])
if mode == noOverloadedSubscript:
bracketNotFoundError(c, result)
return n
else:
result = semExprNoType(c, result) result = semExprNoType(c, result)
c.p.bracketExpr = oldBracketExpr c.p.bracketExpr = oldBracketExpr
return result return result
elif a == nil:
localError(n.info, "could not resolve: " & $n[0])
return n
c.p.bracketExpr = oldBracketExpr c.p.bracketExpr = oldBracketExpr
of nkCurlyExpr: of nkCurlyExpr:
# a{i} = x --> `{}=`(a, i, x) # a{i} = x --> `{}=`(a, i, x)
@ -1557,8 +1636,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
result.flags = {sfGenSym} result.flags = {sfGenSym}
proc semExpandToAst(c: PContext, n: PNode): PNode = proc semExpandToAst(c: PContext, n: PNode): PNode =
var macroCall = n[1] let macroCall = n[1]
var expandedSym = expectMacroOrTemplateCall(c, macroCall) let expandedSym = expectMacroOrTemplateCall(c, macroCall)
if expandedSym.kind == skError: return n if expandedSym.kind == skError: return n
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
@ -1566,11 +1645,12 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
styleCheckUse(n.info, expandedSym) styleCheckUse(n.info, expandedSym)
for i in countup(1, macroCall.len-1): for i in countup(1, macroCall.len-1):
#if macroCall.sons[0].typ.sons[i].kind != tyExpr:
macroCall.sons[i] = semExprWithType(c, macroCall[i], {}) macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
# Preserve the magic symbol in order to be handled in evals.nim # Preserve the magic symbol in order to be handled in evals.nim
internalAssert n.sons[0].sym.magic == mExpandToAst 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" n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
else: sysTypeFromName"PNimrodNode" else: sysTypeFromName"PNimrodNode"
result = n 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. # the correct branch. Otherwise the AST will be passed through semStmt.
result = nil result = nil
template setResult(e: expr) = template setResult(e: untyped) =
if semCheck: result = semStmt(c, e) # do not open a new scope! if semCheck: result = semExpr(c, e) # do not open a new scope!
else: result = e else: result = e
# Check if the node is "when nimvm" # Check if the node is "when nimvm"
@ -1820,6 +1900,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# else: # else:
# ... # ...
var whenNimvm = false var whenNimvm = false
var typ = commonTypeBegin
if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
n.sons[1].kind == nkElse: n.sons[1].kind == nkElse:
let exprNode = n.sons[0].sons[0] let exprNode = n.sons[0].sons[0]
@ -1836,7 +1917,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2) checkSonsLen(it, 2)
if whenNimvm: if whenNimvm:
if semCheck: 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 result = n # when nimvm is not elimited until codegen
else: else:
var e = semConstExpr(c, it.sons[0]) var e = semConstExpr(c, it.sons[0])
@ -1850,12 +1932,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 1) checkSonsLen(it, 1)
if result == nil or whenNimvm: if result == nil or whenNimvm:
if semCheck: 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: if result == nil:
result = it.sons[0] result = it.sons[0]
else: illFormedAst(n) else: illFormedAst(n)
if result == nil: if result == nil:
result = newNodeI(nkEmpty, n.info) result = newNodeI(nkEmpty, n.info)
if whenNimvm: result.typ = typ
# The ``when`` statement implements the mechanism for platform dependent # The ``when`` statement implements the mechanism for platform dependent
# code. Thus we try to ensure here consistent ID allocation after the # code. Thus we try to ensure here consistent ID allocation after the
# ``when`` statement. # ``when`` statement.
@ -2132,7 +2216,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if nfSem in n.flags: return if nfSem in n.flags: return
case n.kind case n.kind
of nkIdent, nkAccQuoted: 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) if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags) result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skConverter, skIterator}: 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: elif n.len == 1:
result = semObjConstr(c, n, flags) result = semObjConstr(c, n, flags)
elif contains(c.ambiguousSymbols, s.id): 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) elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags) else: result = semMagic(c, n, s, flags)
of skProc, skMethod, skConverter, skIterator: 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") if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
result = evalFrom(c, n) result = evalFrom(c, n)
of nkIncludeStmt: of nkIncludeStmt:
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include") #if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
result = evalInclude(c, n) result = evalInclude(c, n)
of nkExportStmt, nkExportExceptStmt: of nkExportStmt, nkExportExceptStmt:
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export") 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} const ordIntLit = {nkIntLit..nkUInt64Lit}
result = n.typ result = n.typ
template commutativeOp(opr: expr) {.immediate.} = template commutativeOp(opr: untyped) =
let a = n.sons[1] let a = n.sons[1]
let b = n.sons[2] let b = n.sons[2]
if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ): 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(pickMinInt(a), pickMinInt(b)),
opr(pickMaxInt(a), pickMaxInt(b))) opr(pickMaxInt(a), pickMaxInt(b)))
template binaryOp(opr: expr) {.immediate.} = template binaryOp(opr: untyped) =
let a = n.sons[1] let a = n.sons[1]
let b = n.sons[2] let b = n.sons[2]
if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}: 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 mNot: result = newIntNodeT(1 - getInt(a), n)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n) of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
of mBitnotI: result = newIntNodeT(not getInt(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 mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
of mLengthSeq, mLengthOpenArray, mXLenSeq: of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit: result = newIntNodeT(0, n) if a.kind == nkNilLit:
else: result = newIntNodeT(sonsLen(a), n) # BUGFIX 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 mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat: of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n) 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)), result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
int(getOrdValue(c))), n) int(getOrdValue(c))), n)
of mFloatToStr: result = newStrNodeT($getFloat(a), 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 mStrToStr: result = a
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
of mArrToSeq: of mArrToSeq:
@ -482,7 +490,7 @@ proc leValueConv(a, b: PNode): bool =
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
case b.kind case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal 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") else: internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
case b.kind case b.kind
@ -627,14 +635,20 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mCompileDate: result = newStrNodeT(times.getDateStr(), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
of mCompileTime: result = newStrNodeT(times.getClockStr(), n) of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n) of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
of mAppType: result = getAppType(n) of mAppType: result = getAppType(n)
of mNaN: result = newFloatNodeT(NaN, n) of mNaN: result = newFloatNodeT(NaN, n)
of mInf: result = newFloatNodeT(Inf, n) of mInf: result = newFloatNodeT(Inf, n)
of mNegInf: result = newFloatNodeT(NegInf, 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: else:
if sfFakeConst notin s.flags: result = copyTree(s.ast) result = copyTree(s.ast)
of {skProc, skMethod}: of {skProc, skMethod}:
result = n result = n
of skType: of skType:

View file

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

View file

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

View file

@ -12,25 +12,26 @@
import ast, astalgo, msgs, types import ast, astalgo, msgs, types
proc ithField(n: PNode, field: int): PSym = proc ithField(n: PNode, field: var int): PSym =
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in countup(0, sonsLen(n) - 1): 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 if result != nil: return
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField") 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 if result != nil: return
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind case n.sons[i].kind
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field-1) result = ithField(lastSon(n.sons[i]), field)
if result != nil: return if result != nil: return
else: internalError(n.info, "ithField(record case branch)") else: internalError(n.info, "ithField(record case branch)")
of nkSym: of nkSym:
if field == 0: result = n.sym if field == 0: result = n.sym
else: dec(field)
else: discard else: discard
proc annotateType*(n: PNode, t: PType) = proc annotateType*(n: PNode, t: PType) =
@ -39,10 +40,13 @@ proc annotateType*(n: PNode, t: PType) =
# to not to skip tyGenericInst # to not to skip tyGenericInst
case n.kind case n.kind
of nkObjConstr: of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t n.typ = t
for i in 1 .. <n.len: for i in 1 .. <n.len:
let field = x.n.ithField(i - 1) var j = i-1
if field.isNil: globalError n.info, "invalid field at index " & $i let field = x.n.ithField(j)
if field.isNil:
globalError n.info, "invalid field at index " & $i
else: else:
internalAssert(n.sons[i].kind == nkExprColonExpr) internalAssert(n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ) 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) result = semSubscript(c, result, flags)
c.p.bracketExpr = oldBracketExpr c.p.bracketExpr = oldBracketExpr
if result.isNil: 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 result = n
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode = 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 = proc semOrd(c: PContext, n: PNode): PNode =
result = n result = n
result.typ = makeRangeType(c, firstOrd(n.sons[1].typ), let parType = n.sons[1].typ
lastOrd(n.sons[1].typ), n.info) 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 = proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n) result = copyNode(n)
@ -130,7 +137,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
return errorNode(c, n) return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info) let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = qualifiedLookUp(c, id) let s = qualifiedLookUp(c, id, {checkUndeclared})
if s != nil: if s != nil:
# we need to mark all symbols: # we need to mark all symbols:
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal)) var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
@ -203,7 +210,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n.sons[1] result = n.sons[1]
else: else:
result = newNodeIT(nkCall, n.info, getSysType(tyInt)) 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 lenExprB
result.add n.sons[1] result.add n.sons[1]
of mPlugin: of mPlugin:

View file

@ -74,8 +74,6 @@ type
currentSpawnId: int currentSpawnId: int
inLoop: int inLoop: int
let opSlice = createMagic("slice", mSlice)
proc initAnalysisCtx(): AnalysisCtx = proc initAnalysisCtx(): AnalysisCtx =
result.locals = @[] result.locals = @[]
result.slices = @[] result.slices = @[]
@ -123,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
else: else:
for i in 0 .. <n.safeLen: checkLocal(c, n.sons[i]) 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) = proc checkLe(c: AnalysisCtx; a, b: PNode) =
case proveLe(c.guards, a, b) 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 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 inc c.spawns
let oldSpawnId = c.currentSpawnId let oldSpawnId = c.currentSpawnId
c.currentSpawnId = c.spawns c.currentSpawnId = c.spawns
@ -399,7 +397,9 @@ proc transformSlices(n: PNode): PNode =
let op = n[0].sym let op = n[0].sym
if op.name.s == "[]" and op.fromSystem: if op.name.s == "[]" and op.fromSystem:
result = copyNode(n) result = copyNode(n)
result.add opSlice.newSymNode let opSlice = newSymNode(createMagic("slice", mSlice))
opSlice.typ = getSysType(tyInt)
result.add opSlice
result.add n[1] result.add n[1]
let slice = n[2].skipStmtList let slice = n[2].skipStmtList
result.add slice[1] result.add slice[1]

View file

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

View file

@ -17,7 +17,8 @@ proc semDiscard(c: PContext, n: PNode): PNode =
checkSonsLen(n, 1) checkSonsLen(n, 1)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0]) 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 = proc semBreakOrContinue(c: PContext, n: PNode): PNode =
result = n result = n
@ -137,7 +138,7 @@ proc fixNilType(n: PNode) =
proc discardCheck(c: PContext, result: PNode) = proc discardCheck(c: PContext, result: PNode) =
if c.inTypeClass > 0: return 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: if result.kind == nkNilLit:
result.typ = nil result.typ = nil
message(result.info, warnNilStatement) message(result.info, warnNilStatement)
@ -303,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode =
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n) result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ, check=true) let r1 = result.sons[1]
result = 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): elif not sameType(result.typ, typ):
changeType(result, typ, check=false) changeType(result, typ, check=false)
@ -336,7 +343,7 @@ proc checkNilable(v: PSym) =
{tfNotNil, tfNeedsInit} * v.typ.flags != {}: {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
if v.ast.isNil: if v.ast.isNil:
message(v.info, warnProveInit, v.name.s) 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) message(v.info, warnProveInit, v.name.s)
include semasgn include semasgn
@ -410,6 +417,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
localError(a.info, "'using' sections cannot contain assignments") 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 = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode var b: PNode
result = copyNode(n) result = copyNode(n)
@ -444,10 +458,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
#changeType(def.skipConv, typ, check=true) #changeType(def.skipConv, typ, check=true)
else: else:
typ = skipIntLit(def.typ) typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and if hasEmpty(typ):
typ.lastSon.kind == tyEmpty:
localError(def.info, errCannotInferTypeOfTheLiteral, localError(def.info, errCannotInferTypeOfTheLiteral,
($typ.kind).substr(2).toLower) ($typ.kind).substr(2).toLowerAscii)
else: else:
def = ast.emptyNode def = ast.emptyNode
if symkind == skLet: localError(a.info, errLetNeedsInit) if symkind == skLet: localError(a.info, errLetNeedsInit)
@ -535,7 +548,7 @@ proc semConst(c: PContext, n: PNode): PNode =
localError(a.sons[2].info, errConstExprExpected) localError(a.sons[2].info, errConstExprExpected)
continue continue
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: 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 continue
v.typ = typ v.typ = typ
v.ast = def # no need to copy v.ast = def # no need to copy
@ -668,7 +681,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
let name = a.sons[0] let name = a.sons[0]
var s: PSym var s: PSym
if name.kind == nkDotExpr: 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: 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") localError(name.info, "only .partial objects can be extended")
else: else:
@ -710,7 +723,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
a.sons[1] = s.typ.n a.sons[1] = s.typ.n
s.typ.size = -1 # could not be computed properly s.typ.size = -1 # could not be computed properly
# we fill it out later. For magic generics like 'seq', it won't be filled # 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 # like: mydata.seq
rawAddSon(s.typ, newTypeS(tyNone, c)) rawAddSon(s.typ, newTypeS(tyNone, c))
s.ast = a s.ast = a
@ -778,11 +791,16 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
var s = a.sons[0].sym var s = a.sons[0].sym
# compute the type's size and check for illegal recursions: # compute the type's size and check for illegal recursions:
if a.sons[1].kind == nkEmpty: 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: # type aliases are hard:
#MessageOut('for type ' + typeToString(s.typ)); var t = semTypeNode(c, x, nil)
var t = semTypeNode(c, a.sons[2], nil) assert t != nil
if t.kind in {tyObject, tyEnum}: if t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t) assignType(s.typ, t)
s.typ.id = t.id # same id s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ) checkConstructedType(s.info, s.typ)
@ -924,6 +942,17 @@ proc semProcAnnotation(c: PContext, prc: PNode;
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas) pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
return 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 = proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually # XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda # remove semLambda
@ -942,8 +971,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
openScope(c) openScope(c)
var gp: PNode var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty: if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) gp = setGenericParamsMisc(c, n)
gp = n.sons[genericParamsPos]
else: else:
gp = newNodeI(nkGenericParams, n.info) gp = newNodeI(nkGenericParams, n.info)
@ -1165,8 +1193,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
openScope(c) openScope(c)
var gp: PNode var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty: if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) gp = setGenericParamsMisc(c, n)
gp = n.sons[genericParamsPos]
else: else:
gp = newNodeI(nkGenericParams, n.info) gp = newNodeI(nkGenericParams, n.info)
# process parameters: # process parameters:
@ -1231,6 +1258,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pushOwner(s) pushOwner(s)
s.options = gOptions s.options = gOptions
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) 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: if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc! # for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags: if sfBorrow in s.flags:
@ -1245,7 +1275,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
c.p.wasForwarded = proto != nil c.p.wasForwarded = proto != nil
maybeAddResult(c, s, n) maybeAddResult(c, s, n)
if sfImportc notin s.flags: if lfDynamicLib notin s.loc.flags:
# no semantic checking for importc: # no semantic checking for importc:
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
# unfortunately we cannot skip this step when in 'system.compiles' # 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 = proc semIterator(c: PContext, n: PNode): PNode =
# gensym'ed iterator? # gensym'ed iterator?
let isAnon = n[namePos].kind == nkEmpty
if n[namePos].kind == nkSym: if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators: # gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner() n[namePos].sym.owner = getCurrOwner()
@ -1294,6 +1325,8 @@ proc semIterator(c: PContext, n: PNode): PNode =
var t = s.typ var t = s.typ
if t.sons[0] == nil and s.typ.callConv != ccClosure: if t.sons[0] == nil and s.typ.callConv != ccClosure:
localError(n.info, errXNeedsReturnType, "iterator") 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, # iterators are either 'inline' or 'closure'; for backwards compatibility,
# we require first class iterators to be marked with 'closure' explicitly # we require first class iterators to be marked with 'closure' explicitly
# -- at least for 0.9.2. # -- at least for 0.9.2.
@ -1325,9 +1358,24 @@ proc finishMethod(c: PContext, s: PSym) =
proc semMethod(c: PContext, n: PNode): PNode = proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas) result = semProcAux(c, n, skMethod, methodPragmas)
# macros can transform methods to nothing:
if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym 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 # why check for the body? bug #2400 has none. Checking for sfForward makes
# no sense either. # no sense either.
# and result.sons[bodyPos].kind != nkEmpty: # 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") if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
result = semProcAux(c, n, skConverter, converterPragmas) 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 s = result.sons[namePos].sym
var t = s.typ var t = s.typ
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter") 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 = proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
result = semProcAux(c, n, skMacro, macroPragmas) 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 s = result.sons[namePos].sym
var t = s.typ var t = s.typ
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro") 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 var i = 0
a = initOverloadIter(o, c, n) a = initOverloadIter(o, c, n)
while a != nil: while a != nil:
a = nextOverloadIter(o, c, n) if a.kind != skModule:
inc(i) inc(i)
if i > 1: break if i > 1: break
a = nextOverloadIter(o, c, n)
if i <= 1 and r != scForceOpen: if i <= 1 and r != scForceOpen:
# XXX this makes more sense but breaks bootstrapping for now: # XXX this makes more sense but breaks bootstrapping for now:
# (s.kind notin routineKinds or s.magic != mNone): # (s.kind notin routineKinds or s.magic != mNone):
@ -68,6 +69,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
result = newNodeIT(kind, n.info, newTypeS(tyNone, c)) result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n) a = initOverloadIter(o, c, n)
while a != nil: while a != nil:
if a.kind != skModule:
incl(a.flags, sfUsed) incl(a.flags, sfUsed)
addSon(result, newSymNode(a, n.info)) addSon(result, newSymNode(a, n.info))
a = nextOverloadIter(o, c, n) a = nextOverloadIter(o, c, n)
@ -80,7 +82,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
# the same symbol! # the same symbol!
# This is however not true anymore for hygienic templates as semantic # This is however not true anymore for hygienic templates as semantic
# processing for them changes the symbol table... # processing for them changes the symbol table...
let s = qualifiedLookUp(c, a) let s = qualifiedLookUp(c, a, {checkUndeclared})
if s != nil: if s != nil:
# we need to mark all symbols: # we need to mark all symbols:
let sc = symChoice(c, n, s, scClosed) let sc = symChoice(c, n, s, scClosed)
@ -577,13 +579,16 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else: else:
gp = newNodeI(nkGenericParams, n.info) gp = newNodeI(nkGenericParams, n.info)
# process parameters: # process parameters:
var allUntyped = true
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[paramsPos], gp, s) semParamList(c, n.sons[paramsPos], gp, s)
# a template's parameters are not gensym'ed even if that was originally the # 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 # case as we determine whether it's a template parameter in the template
# body by the absence of the sfGenSym flag: # body by the absence of the sfGenSym flag:
for i in 1 .. s.typ.n.len-1: 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 sonsLen(gp) > 0:
if n.sons[genericParamsPos].kind == nkEmpty: if n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters: # 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) s.typ.n = newNodeI(nkFormalParams, n.info)
rawAddSon(s.typ, newTypeS(tyStmt, c)) rawAddSon(s.typ, newTypeS(tyStmt, c))
addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0])) addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
if allUntyped: incl(s.flags, sfAllUntyped)
if n.sons[patternPos].kind != nkEmpty: if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos]) n.sons[patternPos] = semPattern(c, n.sons[patternPos])
var ctx: TemplCtx var ctx: TemplCtx
@ -628,8 +634,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
c.patterns.add(s) c.patterns.add(s)
proc semPatternBody(c: var TemplCtx, n: PNode): PNode = proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
template templToExpand(s: expr): expr = template templToExpand(s: untyped): untyped =
s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags) s.kind == skTemplate and (s.typ.len == 1 or sfAllUntyped in s.flags)
proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode = proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
# the param added in the current scope is actually wrong here for # 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: if n.len < 1:
result = newConstraint(c, kind) result = newConstraint(c, kind)
else: 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 let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var base = semTypeNode(c, n.lastSon, nil) 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) result.n = newNodeI(nkRecList, n.info)
var check = initIntSet() var check = initIntSet()
var counter = 0 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] var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a) if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3) checkMinSonsLen(a, 3)
@ -393,20 +393,24 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
addSon(result.n, newSymNode(field)) addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ) addSonSkipIntLit(result, typ)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field) 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, proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym = allowed: TSymFlags): PSym =
# identifier with visibility # identifier with visibility
if n.kind == nkPostfix: 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 # for gensym'ed identifiers the identifier may already have been
# transformed to a symbol and we need to use that here: # transformed to a symbol and we need to use that here:
result = newSymG(kind, n.sons[1], c) 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): if sfExported in allowed and v.id == ord(wStar):
incl(result.flags, sfExported) incl(result.flags, sfExported)
else: 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: else:
illFormedAst(n) illFormedAst(n)
else: else:
@ -751,18 +755,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
addDecl(c, s) addDecl(c, s)
# XXX: There are codegen errors if this is turned into a nested proc # 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) liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
#proc liftingWalk(paramType: PType, anon = false): PType = #proc liftingWalk(paramType: PType, anon = false): PType =
var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
else: nil else: nil
template maybeLift(typ: PType): expr = template maybeLift(typ: PType): untyped =
let lifted = liftingWalk(typ) let lifted = liftingWalk(typ)
(if lifted != nil: lifted else: typ) (if lifted != nil: lifted else: typ)
template addImplicitGeneric(e: expr): expr = template addImplicitGeneric(e): untyped =
addImplicitGenericImpl(e, paramTypId) addImplicitGenericImpl(e, paramTypId)
case paramType.kind: case paramType.kind:
@ -942,7 +946,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if isType: localError(a.info, "':' expected") if isType: localError(a.info, "':' expected")
if kind in {skTemplate, skMacro}: if kind in {skTemplate, skMacro}:
typ = newTypeS(tyExpr, c) typ = newTypeS(tyExpr, c)
elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty: elif skipTypes(typ, {tyGenericInst}).kind == tyVoid:
continue continue
for j in countup(0, length-3): for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c) var arg = newSymG(skParam, a.sons[j], c)
@ -974,7 +978,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if r != nil: if r != nil:
# turn explicit 'void' return type into 'nil' because the rest of the # turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil': # 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: # 'auto' as a return type does not imply a generic:
if r.kind == tyAnything: if r.kind == tyAnything:
# 'p(): auto' and 'p(): expr' are equivalent, but the rest of the # '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 = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil: if s.typ == nil:
localError(n.info, "cannot instantiate the '$1' $2" % 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) return newOrPrevType(tyError, prev, c)
var t = s.typ 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, result = instGenericContainer(c, n.info, result,
allowMetaTypes = false) allowMetaTypes = false)
proc semTypeExpr(c: PContext, n: PNode): PType = proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
var n = semExprWithType(c, n, {efDetermineType}) var n = semExprWithType(c, n, {efDetermineType})
if n.typ.kind == tyTypeDesc: if n.typ.kind == tyTypeDesc:
result = n.typ.base 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: else:
localError(n.info, errTypeExpected, n.renderTree) localError(n.info, errTypeExpected, n.renderTree)
result = errorType(c) result = errorType(c)
@ -1177,7 +1185,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else: else:
localError(n.info, errGenerated, "invalid type") localError(n.info, errGenerated, "invalid type")
elif n[0].kind notin nkIdentKinds: elif n[0].kind notin nkIdentKinds:
result = semTypeExpr(c, n) result = semTypeExpr(c, n, prev)
else: else:
let op = considerQuotedIdent(n.sons[0]) let op = considerQuotedIdent(n.sons[0])
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": 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}) let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
result = typExpr.typ result = typExpr.typ
else: else:
result = semTypeExpr(c, n) result = semTypeExpr(c, n, prev)
of nkWhenStmt: of nkWhenStmt:
var whenResult = semWhen(c, n, false) var whenResult = semWhen(c, n, false)
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType 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) result = copyType(result, getCurrOwner(), false)
for i in countup(1, n.len - 1): for i in countup(1, n.len - 1):
result.rawAddSon(semTypeNode(c, n.sons[i], nil)) 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) else: result = semGeneric(c, n, s, prev)
of nkDotExpr: of nkDotExpr:
var typeExpr = semExpr(c, n) var typeExpr = semExpr(c, n)
@ -1370,10 +1391,7 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicType(m, tyTypeDesc, 0) setMagicType(m, tyTypeDesc, 0)
rawAddSon(m.typ, newTypeS(tyNone, c)) rawAddSon(m.typ, newTypeS(tyNone, c))
of mVoidType: of mVoidType:
setMagicType(m, tyEmpty, 0) setMagicType(m, tyVoid, 0)
# for historical reasons we conflate 'void' with 'empty' so that '@[]'
# has the type 'seq[void]'.
m.typ.flags.incl tfVoid
of mArray: of mArray:
setMagicType(m, tyArray, 0) setMagicType(m, tyArray, 0)
of mOpenArray: of mOpenArray:

View file

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

View file

@ -22,7 +22,7 @@ type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
CandidateErrors* = seq[PSym] CandidateErrors* = seq[(PSym,int)]
TCandidate* = object TCandidate* = object
c*: PContext c*: PContext
exactMatches*: int # also misused to prefer iters over procs exactMatches*: int # also misused to prefer iters over procs
@ -49,6 +49,7 @@ type
# a distrinct type # a distrinct type
typedescMatched*: bool typedescMatched*: bool
isNoCall*: bool # misused for generic type instantiations C[T] isNoCall*: bool # misused for generic type instantiations C[T]
mutabilityProblem*: uint8 # tyVar mismatch
inheritancePenalty: int # to prefer closest father object type inheritancePenalty: int # to prefer closest father object type
errors*: CandidateErrors # additional clarifications to be displayed to the errors*: CandidateErrors # additional clarifications to be displayed to the
# user if overload resolution fails # user if overload resolution fails
@ -96,8 +97,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
c.calleeSym = nil c.calleeSym = nil
initIdTable(c.bindings) initIdTable(c.bindings)
proc put(t: var TIdTable, key, val: PType) {.inline.} = proc put(c: var TCandidate, key, val: PType) {.inline.} =
idTablePut(t, key, val.skipIntLit) idTablePut(c.bindings, key, val.skipIntLit)
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
binding: PNode, calleeScope = -1) = binding: PNode, calleeScope = -1) =
@ -129,7 +130,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
bound = makeTypeDesc(ctx, bound) bound = makeTypeDesc(ctx, bound)
else: else:
bound = bound.skipTypes({tyTypeDesc}) bound = bound.skipTypes({tyTypeDesc})
put(c.bindings, formalTypeParam, bound) put(c, formalTypeParam, bound)
proc newCandidate*(ctx: PContext, callee: PSym, proc newCandidate*(ctx: PContext, callee: PSym,
binding: PNode, calleeScope = -1): TCandidate = binding: PNode, calleeScope = -1): TCandidate =
@ -220,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return if result != 0: return
result = a.convMatches - b.convMatches result = a.convMatches - b.convMatches
if result != 0: return if result != 0: return
result = a.calleeScope - b.calleeScope
if result != 0: return
# the other way round because of other semantics: # the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty result = b.inheritancePenalty - a.inheritancePenalty
if result != 0: return if result != 0: return
# prefer more specialized generic over more general generic: # prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee) 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) = proc writeMatches*(c: TCandidate) =
writeLine(stdout, "exact matches: " & $c.exactMatches) writeLine(stdout, "exact matches: " & $c.exactMatches)
@ -242,6 +244,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
for i in 1 .. <arg.len: for i in 1 .. <arg.len:
result.add(" | ") result.add(" | ")
result.add typeToString(arg[i].typ, prefer) result.add typeToString(arg[i].typ, prefer)
elif arg.typ == nil:
result = "void"
else: else:
result = arg.typ.typeToString(prefer) result = arg.typ.typeToString(prefer)
@ -253,15 +257,16 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
if n.sons[i].kind == nkExprEqExpr: if n.sons[i].kind == nkExprEqExpr:
add(result, renderTree(n.sons[i].sons[0])) add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ") 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]) arg = c.semOperand(c, n.sons[i].sons[1])
n.sons[i].typ = arg.typ n.sons[i].typ = arg.typ
n.sons[i].sons[1] = arg n.sons[i].sons[1] = arg
else: else:
if arg.typ.isNil: if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
arg = c.semOperand(c, n.sons[i]) arg = c.semOperand(c, n.sons[i])
n.sons[i] = arg 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)) add(result, argTypeToString(arg, prefer))
if i != sonsLen(n) - 1: add(result, ", ") if i != sonsLen(n) - 1: add(result, ", ")
@ -360,6 +365,50 @@ proc isObjectSubtype(a, f: PType): int =
if t != nil: if t != nil:
result = depth 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 = proc minRel(a, b: TTypeRelation): TTypeRelation =
if a <= b: result = a if a <= b: result = a
else: result = b else: result = b
@ -513,7 +562,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
proc matchUserTypeClass*(c: PContext, m: var TCandidate, proc matchUserTypeClass*(c: PContext, m: var TCandidate,
ff, a: PType): TTypeRelation = ff, a: PType): TTypeRelation =
var body = ff.skipTypes({tyUserTypeClassInst}) 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") localError(body.n[3].info, $body.n[3] & " too nested for type matching")
return isNone return isNone
@ -531,7 +580,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
typ = ff.sons[i] typ = ff.sons[i]
param: PSym param: PSym
template paramSym(kind): expr = template paramSym(kind): untyped =
newSym(kind, typeParamName, body.sym, body.sym.info) newSym(kind, typeParamName, body.sym, body.sym.info)
case typ.kind case typ.kind
@ -598,6 +647,10 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil) let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
result = c.c.semExpr(c.c, instantiated) 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 = proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# typeRel can be used to establish various relationships between types: # 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) assert(f != nil)
if f.kind == tyExpr: if f.kind == tyExpr:
if aOrig != nil: put(c.bindings, f, aOrig) if aOrig != nil: put(c, f, aOrig)
return isGeneric return isGeneric
assert(aOrig != nil) assert(aOrig != nil)
@ -640,10 +693,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
template bindingRet(res) = template bindingRet(res) =
if doBind: if doBind:
let bound = aOrig.skipTypes({tyRange}).skipIntLit let bound = aOrig.skipTypes({tyRange}).skipIntLit
if doBind: put(c.bindings, f, bound) put(c, f, bound)
return res return res
template considerPreviousT(body: stmt) {.immediate.} = template considerPreviousT(body: untyped) =
var prev = PType(idTableGet(c.bindings, f)) var prev = PType(idTableGet(c.bindings, f))
if prev == nil: body if prev == nil: body
else: return typeRel(c, prev, a) else: return typeRel(c, prev, a)
@ -737,6 +790,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyVar: of tyVar:
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base) if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
else: result = typeRel(c, f.base, aOrig) else: result = typeRel(c, f.base, aOrig)
subtypeCheck()
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
# tyArrayConstr cannot happen really, but # tyArrayConstr cannot happen really, but
# we wanna be safe here # we wanna be safe here
@ -746,7 +800,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if fRange.kind == tyGenericParam: if fRange.kind == tyGenericParam:
var prev = PType(idTableGet(c.bindings, fRange)) var prev = PType(idTableGet(c.bindings, fRange))
if prev == nil: if prev == nil:
put(c.bindings, fRange, a.sons[0]) put(c, fRange, a.sons[0])
fRange = a fRange = a
else: else:
fRange = prev 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 # we must correct for the off-by-one discrepancy between
# ranges and static params: # ranges and static params:
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1) replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
put(c.bindings, rangeStaticT, replacementT) put(c, rangeStaticT, replacementT)
return isGeneric return isGeneric
let len = tryResolvingStaticExpr(c, fRange.n[1]) 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 if sameDistinctTypes(f, a): result = isEqual
elif f.base.kind == tyAnything: result = isGeneric elif f.base.kind == tyAnything: result = isGeneric
elif c.coerceDistincts: result = typeRel(c, f.base, a) 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) elif c.coerceDistincts: result = typeRel(c, f.base, a)
of tySet: of tySet:
if a.kind == 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: for i in 0..f.len-2:
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
result = typeRel(c, f.lastSon, a.lastSon) result = typeRel(c, f.lastSon, a.lastSon)
subtypeCheck()
if result <= isConvertible: result = isNone if result <= isConvertible: result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags: elif tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion result = isNilConversion
@ -921,8 +978,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isConvertible result = isConvertible
else: discard else: discard
of tyEmpty: of tyEmpty, tyVoid:
if a.kind == tyEmpty: result = isEqual if a.kind == f.kind: result = isEqual
of tyGenericInst: of tyGenericInst:
result = typeRel(c, lastSon(f), a) 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: if a.kind == tyGenericInst and a.sons[0] == f:
bindingRet isGeneric bindingRet isGeneric
let ff = lastSon(f) let ff = lastSon(f)
if ff != nil: result = typeRel(c, ff, a) if ff != nil:
result = typeRel(c, ff, a)
of tyGenericInvocation: of tyGenericInvocation:
var x = a.skipGenericAlias var x = a.skipGenericAlias
var depth = 0
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody: if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
# simply no match for now: # simply no match for now:
discard discard
elif x.kind == tyGenericInst and 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)): (sonsLen(x) - 1 == sonsLen(f)):
for i in countup(1, sonsLen(f) - 1): for i in countup(1, sonsLen(f) - 1):
if x.sons[i].kind == tyGenericParam: if x.sons[i].kind == tyGenericParam:
internalError("wrong instantiated type!") 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 result = isGeneric
else: else:
let genericBody = f.sons[0] 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: # we steal the generic parameters from the tyGenericBody:
for i in countup(1, sonsLen(f) - 1): 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: if x == nil:
discard "maybe fine (for eg. a==tyNil)" discard "maybe fine (for eg. a==tyNil)"
elif x.kind in {tyGenericInvocation, tyGenericParam}: elif x.kind in {tyGenericInvocation, tyGenericParam}:
internalError("wrong instantiated type!") internalError("wrong instantiated type!")
else: else:
put(c.bindings, f.sons[i], x) put(c, f.sons[i], x)
of tyAnd: of tyAnd:
considerPreviousT: considerPreviousT:
@ -979,6 +1041,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if x < isSubtype: return isNone if x < isSubtype: return isNone
# 'and' implies minimum matching result: # 'and' implies minimum matching result:
if x < result: result = x if x < result: result = x
if result > isGeneric: result = isGeneric
bindingRet result bindingRet result
of tyOr: of tyOr:
@ -989,6 +1052,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# 'or' implies maximum matching result: # 'or' implies maximum matching result:
if x > result: result = x if x > result: result = x
if result >= isSubtype: if result >= isSubtype:
if result > isGeneric: result = isGeneric
bindingRet result bindingRet result
else: else:
result = isNone result = isNone
@ -1005,7 +1069,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
considerPreviousT: considerPreviousT:
var concrete = concreteType(c, a) var concrete = concreteType(c, a)
if concrete != nil and doBind: if concrete != nil and doBind:
put(c.bindings, f, concrete) put(c, f, concrete)
return isGeneric return isGeneric
of tyBuiltInTypeClass: of tyBuiltInTypeClass:
@ -1013,7 +1077,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
let targetKind = f.sons[0].kind let targetKind = f.sons[0].kind
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
(targetKind in {tyProc, tyPointer} and a.kind == tyNil): (targetKind in {tyProc, tyPointer} and a.kind == tyNil):
put(c.bindings, f, a) put(c, f, a)
return isGeneric return isGeneric
else: else:
return isNone return isNone
@ -1022,7 +1086,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
considerPreviousT: considerPreviousT:
result = matchUserTypeClass(c.c, c, f, aOrig) result = matchUserTypeClass(c.c, c, f, aOrig)
if result == isGeneric: if result == isGeneric:
put(c.bindings, f, a) put(c, f, a)
of tyCompositeTypeClass: of tyCompositeTypeClass:
considerPreviousT: considerPreviousT:
@ -1038,7 +1102,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else: else:
result = typeRel(c, rootf.lastSon, a) result = typeRel(c, rootf.lastSon, a)
if result != isNone: if result != isNone:
put(c.bindings, f, a) put(c, f, a)
result = isGeneric result = isGeneric
of tyGenericParam: of tyGenericParam:
var x = PType(idTableGet(c.bindings, f)) 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}: if doBind and result notin {isNone, isGeneric}:
let concrete = concreteType(c, a) let concrete = concreteType(c, a)
if concrete == nil: return isNone if concrete == nil: return isNone
put(c.bindings, f, concrete) put(c, f, concrete)
else: else:
result = isGeneric result = isGeneric
@ -1086,7 +1150,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if concrete == nil: if concrete == nil:
return isNone return isNone
if doBind: if doBind:
put(c.bindings, f, concrete) put(c, f, concrete)
elif result > isGeneric: elif result > isGeneric:
result = isGeneric result = isGeneric
elif a.kind == tyEmpty: 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 result != isNone and f.n != nil:
if not exprStructuralEquivalent(f.n, aOrig.n): if not exprStructuralEquivalent(f.n, aOrig.n):
result = isNone result = isNone
if result != isNone: put(c.bindings, f, aOrig) if result != isNone: put(c, f, aOrig)
else: else:
result = isNone result = isNone
elif prev.kind == tyStatic: 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) result = typeRel(c, f.base, a.base)
if result != isNone: if result != isNone:
put(c.bindings, f, a) put(c, f, a)
else: else:
if tfUnresolved in f.flags: if tfUnresolved in f.flags:
result = typeRel(c, prev.base, a) result = typeRel(c, prev.base, a)
@ -1151,7 +1215,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyStmt: of tyStmt:
if aOrig != nil and tfOldSchoolExprStmt notin f.flags: if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
put(c.bindings, f, aOrig) put(c, f, aOrig)
result = isGeneric result = isGeneric
of tyProxy: of tyProxy:
@ -1256,6 +1320,13 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if r == isGeneric: if r == isGeneric:
result.typ = getInstantiatedType(c, arg, m, base(f)) result.typ = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true 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) = proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
case r case r
@ -1399,7 +1470,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenSubConv, f, arg, m, c) result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isNone: 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}: if a.kind in {tyProxy, tyUnknown}:
inc(m.genericMatches) inc(m.genericMatches)
m.fauxMatch = a.kind m.fauxMatch = a.kind
@ -1420,6 +1491,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
m.baseTypeMatch = true m.baseTypeMatch = true
else: else:
result = userConvMatch(c, m, base(f), a, arg) result = userConvMatch(c, m, base(f), a, arg)
if result != nil: m.baseTypeMatch = true
proc paramTypesMatch*(m: var TCandidate, f, a: PType, proc paramTypesMatch*(m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode = arg, argOrig: PNode): PNode =
@ -1532,13 +1604,13 @@ proc incrIndexType(t: PType) =
assert t.kind == tyArrayConstr assert t.kind == tyArrayConstr
inc t.sons[0].n.sons[1].intVal 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 x.kind == tyVarargs and x.sons[0].kind == tyExpr and
tfOldSchoolExprStmt notin x.sons[0].flags tfOldSchoolExprStmt notin x.sons[0].flags
proc matchesAux(c: PContext, n, nOrig: PNode, proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var IntSet) = m: var TCandidate, marker: var IntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} = template checkConstraint(n: untyped) {.dirty.} =
if not formal.constraint.isNil: if not formal.constraint.isNil:
if matchNodeKinds(formal.constraint, n): if matchNodeKinds(formal.constraint, n):
# better match over other routines with no such restriction: # 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 formal.typ.kind == tyVar:
if not n.isLValue: if not n.isLValue:
m.state = csNoMatch m.state = csNoMatch
m.mutabilityProblem = uint8(f-1)
return return
var var
@ -1568,6 +1641,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
while a < n.len: while a < n.len:
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
incl(marker, formal.position)
if container.isNil: if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, container) 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 # beware of the side-effects in 'prepareOperand'! So only do it for
# varargs matching. See tests/metatype/tstatic_overloading. # varargs matching. See tests/metatype/tstatic_overloading.
m.baseTypeMatch = false m.baseTypeMatch = false
incl(marker, formal.position)
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
@ -1653,6 +1728,15 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
return return
if formal.typ.isVarargsUntyped:
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
setSon(m.call, formal.position + 1, container)
else:
incrIndexType(container.typ)
addSon(container, n.sons[a])
else:
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
@ -1707,15 +1791,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if formal.ast == nil: if formal.ast == nil:
if formal.typ.kind == tyVarargs: if formal.typ.kind == tyVarargs:
var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, setSon(m.call, formal.position + 1,
container, m, c)) implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
else: else:
# no default value # no default value
m.state = csNoMatch m.state = csNoMatch
break break
else: else:
# use default value: # 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) inc(f)
proc argtypeMatches*(c: PContext, f, a: PType): bool = proc argtypeMatches*(c: PContext, f, a: PType): bool =
@ -1728,16 +1815,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
result = res != nil result = res != nil
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.procvar.} = op: TTypeAttachedOp; col: int): PSym {.procvar.} =
var m: TCandidate var m: TCandidate
initCandidate(c, m, dc.typ) 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 op == attachedDeepCopy:
if f.kind in {tyRef, tyPtr}: f = f.lastSon if f.kind in {tyRef, tyPtr}: f = f.lastSon
else: else:
if f.kind == tyVar: f = f.lastSon if f.kind == tyVar: f = f.lastSon
if typeRel(m, f, t) == isNone: if typeRel(m, f, t) == isNone:
localError(info, errGenerated, "cannot instantiate 'deepCopy'") localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
else: else:
result = c.semGenerateInstance(c, dc, m.bindings, info) result = c.semGenerateInstance(c, dc, m.bindings, info)
assert sfFromGeneric in result.flags assert sfFromGeneric in result.flags
@ -1745,7 +1835,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
include suggest include suggest
when not declared(tests): when not declared(tests):
template tests(s: stmt) {.immediate.} = discard template tests(s: untyped) = discard
tests: tests:
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) 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)) suggestResult(symToSuggest(s, isLocal=true, $ideSug, 100))
inc outputs inc outputs
template wholeSymTab(cond, section: expr) {.immediate.} = template wholeSymTab(cond, section: untyped) =
var isLocal = true var isLocal = true
for scope in walkScopes(c.currentScope): for scope in walkScopes(c.currentScope):
if scope == c.topLevelScope: isLocal = false 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) = proc markUsed(info: TLineInfo; s: PSym) =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil:
incl(s.owner.flags, sfUsed)
if {sfDeprecated, sfError} * s.flags != {}: if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
if sfError in s.flags: localError(info, errWrongSymbolX, 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 = proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info) let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
r.typ = skipTypes(typ, {tyGenericInst}) r.typ = typ #skipTypes(typ, {tyGenericInst})
incl(r.flags, sfFromGeneric) incl(r.flags, sfFromGeneric)
let owner = getCurrOwner(c) let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly: if owner.isIterator and not c.tooEarly:
@ -204,13 +204,7 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
if it.kind != nkConstDef: internalError(it.info, "transformConstSection") if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
if it.sons[0].kind != nkSym: if it.sons[0].kind != nkSym:
internalError(it.info, "transformConstSection") 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 = proc hasContinue(n: PNode): bool =
@ -414,8 +408,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = newTransNode(nkChckRange, n, 3) result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar) dest = skipTypes(n.typ, abstractVar)
result[0] = transform(c, n.sons[1]) result[0] = transform(c, n.sons[1])
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
# XXX int64 -> float conversion? # XXX int64 -> float conversion?
if skipTypes(n.typ, abstractVar).kind == tyRange: if skipTypes(n.typ, abstractVar).kind == tyRange:
@ -480,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
type type
TPutArgInto = enum TPutArgInto = enum
paDirectMapping, paFastAsgn, paVarAsgn paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
proc putArgInto(arg: PNode, formal: PType): TPutArgInto = proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
# This analyses how to treat the mapping "formal <-> arg" in an # This analyses how to treat the mapping "formal <-> arg" in an
# inline context. # inline context.
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
if arg.kind == nkStmtListExpr:
return paComplexOpenarray
return paDirectMapping # XXX really correct? return paDirectMapping # XXX really correct?
# what if ``arg`` has side-effects? # what if ``arg`` has side-effects?
case arg.kind case arg.kind
@ -575,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
assert(skipTypes(formal.typ, abstractInst).kind == tyVar) assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
idNodeTablePut(newC.mapping, formal, arg) idNodeTablePut(newC.mapping, formal, arg)
# XXX BUG still not correct if the arg has a side effect! # 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 var body = iter.getBody.copyTree
pushInfoContext(n.info) pushInfoContext(n.info)
# XXX optimize this somehow. But the check "c.inlining" is not correct: # 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
else: result = mNone else: result = mNone
proc treeToSym*(t: PNode): PSym =
result = t.sym
proc isConstExpr*(n: PNode): bool = proc isConstExpr*(n: PNode): bool =
result = (n.kind in result = (n.kind in
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags) 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 = proc isDeepConstExpr*(n: PNode): bool =
case n.kind case n.kind
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
@ -119,11 +121,14 @@ proc isDeepConstExpr*(n: PNode): bool =
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv: of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1]) result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure: 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 if not isDeepConstExpr(n.sons[i]): return false
# XXX once constant objects are supported by the codegen this needs to be if n.typ.isNil: result = true
# weakened: else:
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject 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 else: discard
proc flattenTreeAux(d, a: PNode, op: TMagic) = proc flattenTreeAux(d, a: PNode, op: TMagic) =

View file

@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool
proc enumHasHoles*(t: PType): bool proc enumHasHoles*(t: PType): bool
const const
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
# replace with typedescX
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable, tyTypeDesc} tyConst, tyMutable, tyTypeDesc}
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
@ -61,6 +63,7 @@ const
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
tyTypeDesc} tyTypeDesc}
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc}
@ -148,10 +151,12 @@ proc skipGeneric(t: PType): PType =
proc isOrdinalType(t: PType): bool = proc isOrdinalType(t: PType): bool =
assert(t != nil) assert(t != nil)
const
# caution: uint, uint64 are no ordinal types! # caution: uint, uint64 are no ordinal types!
result = t.kind in {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} or baseKinds = {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum}
(t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and parentKinds = {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst,
isOrdinalType(t.sons[0]) tyDistinct}
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
proc enumHasHoles(t: PType): bool = proc enumHasHoles(t: PType): bool =
var b = t var b = t
@ -407,7 +412,8 @@ const
"!", "varargs[$1]", "iter[$1]", "Error Type", "!", "varargs[$1]", "iter[$1]", "Error Type",
"BuiltInTypeClass", "UserTypeClass", "BuiltInTypeClass", "UserTypeClass",
"UserTypeClassInst", "CompositeTypeClass", "UserTypeClassInst", "CompositeTypeClass",
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"] "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
"void"]
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
@ -540,7 +546,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
else: else:
result.add typeToString(t.sons[0]) result.add typeToString(t.sons[0])
of tyRange: 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: if prefer != preferExported:
result.add("(" & typeToString(t.sons[0]) & ")") result.add("(" & typeToString(t.sons[0]) & ")")
of tyProc: of tyProc:
@ -727,6 +735,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
result = paramsNotEqual result = paramsNotEqual
proc sameConstraints(a, b: PNode): bool = proc sameConstraints(a, b: PNode): bool =
if isNil(a) and isNil(b): return true
internalAssert a.len == b.len internalAssert a.len == b.len
for i in 1 .. <a.len: for i in 1 .. <a.len:
if not exprStructuralEquivalent(a[i].sym.constraint, 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 result = x.name.id == y.name.id
if not result: break if not result: break
else: internalError(a.n.info, "sameTuple") 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: if tfFromGeneric notin a.flags + b.flags:
# fast case: id comparison suffices: # fast case: id comparison suffices:
result = a.id == b.id 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] while a.kind == tyDistinct: a = a.sons[0]
if a.kind != b.kind: return false 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 let
lhs = x.skipGenericAlias lhs = x.skipGenericAlias
rhs = y.skipGenericAlias rhs = y.skipGenericAlias
@ -922,7 +934,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
case a.kind case a.kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyStmt, tyExpr: tyInt..tyBigNum, tyStmt, tyExpr, tyVoid:
result = sameFlags(a, b) result = sameFlags(a, b)
of tyStatic, tyFromExpr: of tyStatic, tyFromExpr:
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b) 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 result = nil
of tyExpr, tyStmt, tyStatic: of tyExpr, tyStmt, tyStatic:
if kind notin {skParam, skResult}: result = t if kind notin {skParam, skResult}: result = t
of tyEmpty: of tyVoid:
if taField notin flags: result = t if taField notin flags: result = t
of tyTypeClasses: of tyTypeClasses:
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t 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 != nil: break
if result.isNil and t.n != nil: if result.isNil and t.n != nil:
result = typeAllowedNode(marker, t.n, kind, flags) 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 # for now same as error node; we say it's a valid type as it should
# prevent cascading errors: # prevent cascading errors:
result = nil result = nil
@ -1313,6 +1325,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyTypeDesc: of tyTypeDesc:
result = computeSizeAux(typ.base, a) result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion of tyForward: return szIllegalRecursion
of tyStatic:
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
else: result = szUnknownSize
else: else:
#internalError("computeSizeAux()") #internalError("computeSizeAux()")
result = szUnknownSize result = szUnknownSize
@ -1448,6 +1463,18 @@ proc skipConv*(n: PNode): PNode =
result = n.sons[1] result = n.sons[1]
else: discard 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 = proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv result = n.skipConv
result.typ = n.typ result.typ = n.typ
@ -1493,3 +1520,12 @@ proc skipHiddenSubConv*(n: PNode): PNode =
result.typ = dest result.typ = dest
else: else:
result = n 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. ## This file implements the new evaluation engine for Nim code.
## An instruction is 1-3 int32s in memory, it is a register based VM. ## 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 import ast except getstr
@ -90,38 +92,38 @@ when not defined(nimComputedGoto):
proc myreset(n: var TFullReg) = reset(n) proc myreset(n: var TFullReg) = reset(n)
template ensureKind(k: expr) {.immediate, dirty.} = template ensureKind(k: untyped) {.dirty.} =
if regs[ra].kind != k: if regs[ra].kind != k:
myreset(regs[ra]) myreset(regs[ra])
regs[ra].kind = k regs[ra].kind = k
template decodeB(k: expr) {.immediate, dirty.} = template decodeB(k: untyped) {.dirty.} =
let rb = instr.regB let rb = instr.regB
ensureKind(k) ensureKind(k)
template decodeBC(k: expr) {.immediate, dirty.} = template decodeBC(k: untyped) {.dirty.} =
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
ensureKind(k) ensureKind(k)
template declBC() {.immediate, dirty.} = template declBC() {.dirty.} =
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
template decodeBImm(k: expr) {.immediate, dirty.} = template decodeBImm(k: untyped) {.dirty.} =
let rb = instr.regB let rb = instr.regB
let imm = instr.regC - byteExcess let imm = instr.regC - byteExcess
ensureKind(k) ensureKind(k)
template decodeBx(k: expr) {.immediate, dirty.} = template decodeBx(k: untyped) {.dirty.} =
let rbx = instr.regBx - wordExcess let rbx = instr.regBx - wordExcess
ensureKind(k) 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 # XXX fix minor 'shallowCopy' overloading bug in compiler
proc createStrKeepNode(x: var TFullReg; keepNode=true) = proc createStrKeepNode(x: var TFullReg; keepNode=true) =
if x.node.isNil: if x.node.isNil or not keepNode:
x.node = newNode(nkStrLit) x.node = newNode(nkStrLit)
elif x.node.kind == nkNilLit and keepNode: elif x.node.kind == nkNilLit and keepNode:
when defined(useNodeIds): 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 # this seems to be the best way to model the reference semantics
# of system.NimNode: # of system.NimNode:
template asgnRef(x, y: expr) = moveConst(x, y) template asgnRef(x, y: untyped) = moveConst(x, y)
proc copyValue(src: PNode): PNode = proc copyValue(src: PNode): PNode =
if src == nil or nfIsRef in src.flags: if src == nil or nfIsRef in src.flags:
@ -231,7 +233,7 @@ proc regToNode(x: TFullReg): PNode =
of rkRegisterAddr: result = regToNode(x.regAddr[]) of rkRegisterAddr: result = regToNode(x.regAddr[])
of rkNodeAddr: result = x.nodeAddr[] 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))) (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
proc pushSafePoint(f: PStackFrame; pc: int) = 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 instr = c.code[pc]
let ra = instr.regA let ra = instr.regA
#if c.traceActive: #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") # message(c.debug[pc], warnUser, "Trace")
case instr.opcode case instr.opcode
@ -542,7 +545,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].node.kind == nkRefTy: if regs[rb].node.kind == nkRefTy:
regs[ra].node = regs[rb].node.sons[0] regs[ra].node = regs[rb].node.sons[0]
else: else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'") stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
else: else:
stackTrace(c, tos, pc, errNilAccess) stackTrace(c, tos, pc, errNilAccess)
of opcWrDeref: of opcWrDeref:
@ -1182,19 +1185,35 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNGetType: of opcNGetType:
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
if rc == 0: case rc:
of 0:
# getType opcode:
ensureKind(rkNode) ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc]) regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
else: else:
stackTrace(c, tos, pc, errGenerated, "node has no type") stackTrace(c, tos, pc, errGenerated, "node has no type")
else: of 1:
# typeKind opcode: # typeKind opcode:
ensureKind(rkInt) ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil: if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind) regs[ra].intVal = ord(regs[rb].node.typ.kind)
#else: #else:
# stackTrace(c, tos, pc, errGenerated, "node has no type") # 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: of opcNStrVal:
decodeB(rkNode) decodeB(rkNode)
createStr regs[ra] createStr regs[ra]
@ -1554,7 +1573,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
var evalMacroCounter: int var evalMacroCounter: int
proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = 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) inc(evalMacroCounter)
if evalMacroCounter > 100: if evalMacroCounter > 100:
globalError(n.info, errTemplateInstantiationTooNested) globalError(n.info, errTemplateInstantiationTooNested)
@ -1584,7 +1603,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
# return value: # return value:
tos.slots[0].kind = rkNode 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: # setup parameters:
for i in 1.. <sym.typ.len: 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) if cyclicTree(result): globalError(n.info, errCyclicTree)
dec(evalMacroCounter) dec(evalMacroCounter)
c.callsite = nil c.callsite = nil
#debug result

View file

@ -230,10 +230,10 @@ const
slotSomeTemp* = slotTempUnknown slotSomeTemp* = slotTempUnknown
relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32) template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32) template regA*(x: TInstr): TRegister = 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 regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32) template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int 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. # 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 = proc readOutput(p: Process): string =
result = "" result = ""
@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string =
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
try: try:
let filename = file.findFile var filename = parentDir(info.toFullPath) / file
if not fileExists(filename):
filename = file.findFile
result = readFile(filename) result = readFile(filename)
# we produce a fake include statement for every slurped filename, so that # we produce a fake include statement for every slurped filename, so that
# the module dependencies are accurate: # the module dependencies are accurate:
@ -61,123 +63,249 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
localError(info, errCannotOpenFile, file) localError(info, errCannotOpenFile, file)
result = "" 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) let sym = newSym(skType, getIdent(name), t.owner, info)
sym.magic = m
sym.typ = t sym.typ = t
result = newSymNode(sym) result = newSymNode(sym)
result.typ = t 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 = 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: for i in 0 .. < t.len:
if t.sons[i] == nil: if t.sons[i] == nil:
let void = atomicTypeX("void", t, info) let void = atomicTypeX("void", mVoid, t, info)
void.typ = newType(tyEmpty, t.owner) void.typ = newType(tyVoid, t.owner)
result.add void result.add void
else: 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 = proc objectNode(n: PNode): PNode =
template atomicType(name): expr = atomicTypeX(name, t, info) 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 case t.kind
of tyNone: result = atomicType("none") of tyNone: result = atomicType("none", mNone)
of tyBool: result = atomicType("bool") of tyBool: result = atomicType("bool", mBool)
of tyChar: result = atomicType("char") of tyChar: result = atomicType("char", mChar)
of tyNil: result = atomicType("nil") of tyNil: result = atomicType("nil", mNil)
of tyExpr: result = atomicType("expr") of tyExpr: result = atomicType("expr", mExpr)
of tyStmt: result = atomicType("stmt") of tyStmt: result = atomicType("stmt", mStmt)
of tyEmpty: result = atomicType"void" of tyVoid: result = atomicType("void", mVoid)
of tyEmpty: result = atomicType("empty", mNone)
of tyArrayConstr, tyArray: of tyArrayConstr, tyArray:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("array") 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[0], info)
result.add mapTypeToAst(t.sons[1], info) result.add mapTypeToAst(t.sons[1], info)
of tyTypeDesc: of tyTypeDesc:
if t.base != nil: if t.base != nil:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) 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) result.add mapTypeToAst(t.base, info)
else: else:
result = atomicType"typeDesc" result = atomicType("typeDesc", mTypeDesc)
of tyGenericInvocation: of tyGenericInvocation:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
for i in 0 .. < t.len: for i in 0 .. < t.len:
result.add mapTypeToAst(t.sons[i], info) 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) result = mapTypeToAst(t.lastSon, info)
of tyDistinct: of tyDistinct:
if allowRecursion: if inst:
result = mapTypeToBracket("distinct", t, info) result = newNodeX(nkDistinctTy)
result.add mapTypeToAst(t.sons[0], info)
else: else:
result = atomicType(t.sym.name.s) if allowRecursion or t.sym == nil:
of tyGenericParam, tyForward: result = atomicType(t.sym.name.s) result = mapTypeToBracket("distinct", mDistinct, t, info)
else:
result = atomicType(t.sym.name.s, t.sym.magic)
of tyGenericParam, tyForward:
result = atomicType(t.sym.name.s, t.sym.magic)
of tyObject: of tyObject:
if allowRecursion: 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:
if allowRecursion or t.sym == nil:
result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t) result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
result.add ast.emptyNode
if t.sons[0] == nil: if t.sons[0] == nil:
result.add ast.emptyNode result.add ast.emptyNode
else: else:
result.add mapTypeToAst(t.sons[0], info) result.add mapTypeToAst(t.sons[0], info)
result.add copyTree(t.n) result.add copyTree(t.n)
else: else:
result = atomicType(t.sym.name.s) result = atomicType(t.sym.name.s, t.sym.magic)
of tyEnum: of tyEnum:
result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t) result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t)
result.add copyTree(t.n) result.add copyTree(t.n)
of tyTuple: result = mapTypeToBracket("tuple", t, info) of tyTuple:
of tySet: result = mapTypeToBracket("set", t, info) if inst:
of tyPtr: result = mapTypeToBracket("ptr", t, info) result = newNodeX(nkTupleTy)
of tyRef: result = mapTypeToBracket("ref", t, info) for s in t.n.sons:
of tyVar: result = mapTypeToBracket("var", t, info) result.add newIdentDefs(s)
of tySequence: result = mapTypeToBracket("seq", t, info) else:
of tyProc: result = mapTypeToBracket("proc", t, info) result = mapTypeToBracket("tuple", mTuple, t, info)
of tyOpenArray: result = mapTypeToBracket("openArray", 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: of tyRange:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t) 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[0].copyTree
result.add t.n.sons[1].copyTree result.add t.n.sons[1].copyTree
of tyPointer: result = atomicType"pointer" of tyPointer: result = atomicType("pointer", mPointer)
of tyString: result = atomicType"string" of tyString: result = atomicType("string", mString)
of tyCString: result = atomicType"cstring" of tyCString: result = atomicType("cstring", mCString)
of tyInt: result = atomicType"int" of tyInt: result = atomicType("int", mInt)
of tyInt8: result = atomicType"int8" of tyInt8: result = atomicType("int8", mInt8)
of tyInt16: result = atomicType"int16" of tyInt16: result = atomicType("int16", mInt16)
of tyInt32: result = atomicType"int32" of tyInt32: result = atomicType("int32", mInt32)
of tyInt64: result = atomicType"int64" of tyInt64: result = atomicType("int64", mInt64)
of tyFloat: result = atomicType"float" of tyFloat: result = atomicType("float", mFloat)
of tyFloat32: result = atomicType"float32" of tyFloat32: result = atomicType("float32", mFloat32)
of tyFloat64: result = atomicType"float64" of tyFloat64: result = atomicType("float64", mFloat64)
of tyFloat128: result = atomicType"float128" of tyFloat128: result = atomicType("float128", mFloat128)
of tyUInt: result = atomicType"uint" of tyUInt: result = atomicType("uint", mUint)
of tyUInt8: result = atomicType"uint8" of tyUInt8: result = atomicType("uint8", mUint8)
of tyUInt16: result = atomicType"uint16" of tyUInt16: result = atomicType("uint16", mUint16)
of tyUInt32: result = atomicType"uint32" of tyUInt32: result = atomicType("uint32", mUint32)
of tyUInt64: result = atomicType"uint64" of tyUInt64: result = atomicType("uint64", mUint64)
of tyBigNum: result = atomicType"bignum" of tyBigNum: result = atomicType("bignum", mNone)
of tyConst: result = mapTypeToBracket("const", t, info) of tyConst: result = mapTypeToBracket("const", mNone, t, info)
of tyMutable: result = mapTypeToBracket("mutable", t, info) of tyMutable: result = mapTypeToBracket("mutable", mNone, t, info)
of tyVarargs: result = mapTypeToBracket("varargs", t, info) of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
of tyIter: result = mapTypeToBracket("iter", t, info) of tyIter: result = mapTypeToBracket("iter", mNone, t, info)
of tyProxy: result = atomicType"error" of tyProxy: result = atomicType("error", mNone)
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info) of tyBuiltInTypeClass:
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
of tyUserTypeClass: of tyUserTypeClass:
result = mapTypeToBracket("concept", t, info) result = mapTypeToBracket("concept", mNone, t, info)
result.add t.n.copyTree result.add t.n.copyTree
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info) of tyCompositeTypeClass:
of tyAnd: result = mapTypeToBracket("and", t, info) result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
of tyOr: result = mapTypeToBracket("or", t, info) of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
of tyNot: result = mapTypeToBracket("not", t, info) of tyOr: result = mapTypeToBracket("or", mOr, t, info)
of tyAnything: result = atomicType"anything" of tyNot: result = mapTypeToBracket("not", mNot, t, info)
of tyAnything: result = atomicType("anything", mNone)
of tyStatic, tyFromExpr, tyFieldAccessor: of tyStatic, tyFromExpr, tyFieldAccessor:
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 = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("static") result.add atomicType("static", mNone)
if t.n != nil: if t.n != nil:
result.add t.n.copyTree result.add t.n.copyTree
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = 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 let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
(b.uint32 shl 16'u32) or (b.uint32 shl 16'u32) or
(c.uint32 shl 24'u32)).TInstr (c.uint32 shl 24'u32)).TInstr
when false:
if ctx.code.len == 43:
writeStackTrace()
echo "generating ", opc
ctx.code.add(ins) ctx.code.add(ins)
ctx.debug.add(n.info) 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) = proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
# Applies `opc` to `bx` and stores it into register `a` # Applies `opc` to `bx` and stores it into register `a`
# `bx` must be signed and in the range [-32768, 32767] # `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: if bx >= -32768 and bx <= 32767:
let ins = (opc.uint32 or a.uint32 shl 8'u32 or let ins = (opc.uint32 or a.uint32 shl 8'u32 or
(bx+wordExcess).uint32 shl 16'u32).TInstr (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) = proc freeTempRange(c: PCtx; start: TRegister, n: int) =
for i in start .. start+n-1: c.freeTemp(TRegister(i)) 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) var tmp = getTemp(c, typ)
body body
c.freeTemp(tmp) c.freeTemp(tmp)
@ -232,7 +241,7 @@ proc popBlock(c: PCtx; oldLen: int) =
c.patch(f) c.patch(f)
c.prc.blocks.setLen(oldLen) 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 var oldLen {.gensym.} = c.prc.blocks.len
c.prc.blocks.add TBlock(label: labl, fixups: @[]) c.prc.blocks.add TBlock(label: labl, fixups: @[])
body body
@ -258,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} = proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
# stmt is different from 'void' in meta programming contexts. # stmt is different from 'void' in meta programming contexts.
# So we only set dest to -1 if 'void': # 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) c.freeTemp(dest)
dest = -1 dest = -1
@ -365,7 +374,7 @@ proc canonValue*(n: PNode): PNode =
proc rawGenLiteral(c: PCtx; n: PNode): int = proc rawGenLiteral(c: PCtx; n: PNode): int =
result = c.constants.len result = c.constants.len
assert(n.kind != nkCall) #assert(n.kind != nkCall)
n.flags.incl nfAllConst n.flags.incl nfAllConst
c.constants.add n.canonValue c.constants.add n.canonValue
internalAssert result < 0x7fff internalAssert result < 0x7fff
@ -488,12 +497,30 @@ proc genReturn(c: PCtx; n: PNode) =
gen(c, n.sons[0]) gen(c, n.sons[0])
c.gABC(n, opcRet) 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) = 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) if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
let x = c.getTempRange(n.len, slotTempUnknown) let x = c.getTempRange(n.len, slotTempUnknown)
# varargs need 'opcSetType' for the FFI support: # 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: 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 var r: TRegister = x+i
c.gen(n.sons[i], r) c.gen(n.sons[i], r)
if i >= fntyp.len: if i >= fntyp.len:
@ -570,16 +597,27 @@ proc genNew(c: PCtx; n: PNode) =
c.freeTemp(dest) c.freeTemp(dest)
proc genNewSeq(c: PCtx; n: PNode) = 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]) else: c.genx(n.sons[1])
let tmp = c.genx(n.sons[2]) 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}))) abstractVar-{tyTypeDesc})))
c.gABx(n, opcNewSeq, tmp, 0) c.gABx(n, opcNewSeq, tmp, 0)
c.freeTemp(tmp) c.freeTemp(tmp)
c.genAsgnPatch(n.sons[1], dest) c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(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) = proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let tmp = c.genx(n.sons[1]) let tmp = c.genx(n.sons[1])
if dest < 0: dest = c.getTemp(n.typ) 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}) let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for # uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types: # other unsigned types:
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
(t.kind == tyInt and t.size == 4):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = 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) c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = 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) let tmp = c.genx(arg)
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opc, dest, tmp) c.gABC(n, opc, dest, tmp)
@ -751,6 +792,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNewSeq: of mNewSeq:
unused(n, dest) unused(n, dest)
c.genNewSeq(n) c.genNewSeq(n)
of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
of mNewString: of mNewString:
genUnaryABC(c, n, dest, opcNewStr) genUnaryABC(c, n, dest, opcNewStr)
# XXX buggy # 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 mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu) of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)
of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu) of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
of mEqProc, mEqRef, mEqUntracedRef, mEqCString: of mEqProc, mEqRef, mEqUntracedRef:
genBinaryABC(c, n, dest, opcEqRef) genBinaryABC(c, n, dest, opcEqRef)
of mXor: genBinaryABCnarrowU(c, n, dest, opcXor) of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
of mNot: genUnaryABC(c, n, dest, opcNot) 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, mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n.sons[1], dest) 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 mLeStr: genBinaryABC(c, n, dest, opcLeStr)
of mLtStr: genBinaryABC(c, n, dest, opcLtStr) of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
of mEqSet: genBinarySet(c, n, dest, opcEqSet) of mEqSet: genBinarySet(c, n, dest, opcEqSet)
@ -970,7 +1012,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNGetType: of mNGetType:
let tmp = c.genx(n.sons[1]) let tmp = c.genx(n.sons[1])
if dest < 0: dest = c.getTemp(n.typ) 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) c.freeTemp(tmp)
#genUnaryABC(c, n, dest, opcNGetType) #genUnaryABC(c, n, dest, opcNGetType)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal) 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): if isAddr and (let m = canElimAddr(n); m != nil):
gen(c, m, dest, flags) gen(c, m, dest, flags)
return 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: # consider:
# proc foo(f: var ref int) = # proc foo(f: var ref int) =
# f = new(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): if gfAddrOf notin flags and fitsRegister(n.typ):
c.gABC(n, opcNodeToReg, dest, dest) c.gABC(n, opcNodeToReg, dest, dest)
elif isAddr and isGlobal(n.sons[0]): elif isAddr and isGlobal(n.sons[0]):
gen(c, n.sons[0], dest, flags+{gfAddrOf}) gen(c, n.sons[0], dest, flags+af)
else: else:
let tmp = c.genx(n.sons[0], newflags) let tmp = c.genx(n.sons[0], newflags)
if dest < 0: dest = c.getTemp(n.typ) 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 = proc isTemp(c: PCtx; dest: TDest): bool =
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown 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) not c.isTemp(dest) and not fitsRegister(n.typ)
proc skipDeref(n: PNode): PNode = proc skipDeref(n: PNode): PNode =
@ -1286,15 +1336,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
let dest = c.genx(le, {gfAddrOf}) let dest = c.genx(le, {gfAddrOf})
genAsgn(c, dest, ri, requiresCopy) 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) = proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
var n = newNode(nkType) var n = newNode(nkType)
n.typ = t n.typ = t
@ -1321,6 +1362,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
# var decls{.compileTime.}: seq[NimNode] = @[] # var decls{.compileTime.}: seq[NimNode] = @[]
let dest = c.getTemp(s.typ) let dest = c.getTemp(s.typ)
c.gABx(n, opcLdGlobal, dest, s.position) c.gABx(n, opcLdGlobal, dest, s.position)
if s.ast != nil:
let tmp = c.genx(s.ast) let tmp = c.genx(s.ast)
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp) c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
c.freeTemp(dest) c.freeTemp(dest)
@ -1361,7 +1403,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
# see tests/t99bott for an example that triggers it: # see tests/t99bott for an example that triggers it:
cannotEval(n) cannotEval(n)
template needsRegLoad(): expr = template needsRegLoad(): untyped =
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar})) gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
@ -1447,12 +1489,12 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyObject: of tyObject:
result = newNodeIT(nkObjConstr, info, t) result = newNodeIT(nkObjConstr, info, t)
result.add(newNodeIT(nkEmpty, info, t)) result.add(newNodeIT(nkEmpty, info, t))
getNullValueAux(t.n, result)
# initialize inherited fields: # initialize inherited fields:
var base = t.sons[0] var base = t.sons[0]
while base != nil: while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result) getNullValueAux(skipTypes(base, skipPtrs).n, result)
base = base.sons[0] base = base.sons[0]
getNullValueAux(t.n, result)
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
result = newNodeIT(nkBracket, info, t) result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1): 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: of skType:
genTypeLit(c, s.typ, dest) genTypeLit(c, s.typ, dest)
of skGenericParam: of skGenericParam:
if c.prc.sym.kind == skMacro: if c.prc.sym != nil and c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags) genRdVar(c, n, dest, flags)
else: else:
internalError(n.info, "cannot generate code for: " & s.name.s) globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
else: else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
of nkCallKinds: of nkCallKinds:
@ -1736,9 +1778,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of declarativeDefs: of declarativeDefs:
unused(n, dest) unused(n, dest)
of nkLambdaKinds: of nkLambdaKinds:
let s = n.sons[namePos].sym #let s = n.sons[namePos].sym
discard genProc(c, s) #discard genProc(c, s)
genLit(c, n.sons[namePos], dest) genLit(c, newSymNode(n.sons[namePos].sym), dest)
of nkChckRangeF, nkChckRange64, nkChckRange: of nkChckRangeF, nkChckRange64, nkChckRange:
let let
tmp0 = c.genx(n.sons[0]) 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) genConv(c, n, n.sons[1], dest, opcCast)
else: else:
globalError(n.info, errGenerated, "VM is not allowed to 'cast'") globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
of nkTypeOfExpr:
genTypeLit(c, n.typ, dest)
else: else:
globalError(n.info, errGenerated, "cannot generate VM code for " & $n) globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
@ -1865,8 +1909,8 @@ proc optimizeJumps(c: PCtx; start: int) =
else: discard else: discard
proc genProc(c: PCtx; s: PSym): int = proc genProc(c: PCtx; s: PSym): int =
let x = s.ast.sons[optimizedCodePos] var x = s.ast.sons[miscPos]
if x.kind == nkEmpty: if x.kind == nkEmpty or x[0].kind == nkEmpty:
#if s.name.s == "outterMacro" or s.name.s == "innerProc": #if s.name.s == "outterMacro" or s.name.s == "innerProc":
# echo "GENERATING CODE FOR ", s.name.s # echo "GENERATING CODE FOR ", s.name.s
let last = c.code.len-1 let last = c.code.len-1
@ -1877,7 +1921,11 @@ proc genProc(c: PCtx; s: PSym): int =
c.debug.setLen(last) c.debug.setLen(last)
#c.removeLastEof #c.removeLastEof
result = c.code.len+1 # skip the jump instruction 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 # thanks to the jmp we can add top level statements easily and also nest
# procs easily: # procs easily:
let body = s.getBody let body = s.getBody
@ -1912,4 +1960,4 @@ proc genProc(c: PCtx; s: PSym): int =
c.prc = oldPrc c.prc = oldPrc
else: else:
c.prc.maxSlots = s.offset 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. # distribution, for details about the copyright.
# #
template setX(k, field) {.immediate, dirty.} = template setX(k, field) {.dirty.} =
var s: seq[TFullReg] var s: seq[TFullReg]
move(s, cast[seq[TFullReg]](a.slots)) move(s, cast[seq[TFullReg]](a.slots))
if s[a.ra].kind != k: 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) for x in v: n.add newStrNode(nkStrLit, x)
s[a.ra].node = n s[a.ra].node = n
template getX(k, field) {.immediate, dirty.} = template getX(k, field) {.dirty.} =
doAssert i < a.rc-1 doAssert i < a.rc-1
let s = cast[seq[TFullReg]](a.slots) let s = cast[seq[TFullReg]](a.slots)
doAssert s[i+a.rb+1].kind == k 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 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`) 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`) 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`) registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
template wrap1f(op) {.immediate, dirty.} = template wrap1f_math(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getFloat(a, 0))) setResult(a, op(getFloat(a, 0)))
mathop op mathop op
template wrap2f(op) {.immediate, dirty.} = template wrap2f_math(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getFloat(a, 0), getFloat(a, 1))) setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
mathop op mathop op
template wrap1s(op) {.immediate, dirty.} = template wrap1s_os(op) {.dirty.} =
proc `op Wrapper`(a: VmArgs) {.nimcall.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} =
setResult(a, op(getString(a, 0))) setResult(a, op(getString(a, 0)))
osop op 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.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} =
op(getString(a, 0), getString(a, 1)) op(getString(a, 0), getString(a, 1))
systemop op systemop op
@ -55,34 +60,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
newStrNode(nkStrLit, f)) newStrNode(nkStrLit, f))
proc registerAdditionalOps*(c: PCtx) = proc registerAdditionalOps*(c: PCtx) =
wrap1f(sqrt) wrap1f_math(sqrt)
wrap1f(ln) wrap1f_math(ln)
wrap1f(log10) wrap1f_math(log10)
wrap1f(log2) wrap1f_math(log2)
wrap1f(exp) wrap1f_math(exp)
wrap1f(round) wrap1f_math(round)
wrap1f(arccos) wrap1f_math(arccos)
wrap1f(arcsin) wrap1f_math(arcsin)
wrap1f(arctan) wrap1f_math(arctan)
wrap2f(arctan2) wrap2f_math(arctan2)
wrap1f(cos) wrap1f_math(cos)
wrap1f(cosh) wrap1f_math(cosh)
wrap2f(hypot) wrap2f_math(hypot)
wrap1f(sinh) wrap1f_math(sinh)
wrap1f(sin) wrap1f_math(sin)
wrap1f(tan) wrap1f_math(tan)
wrap1f(tanh) wrap1f_math(tanh)
wrap2f(pow) wrap2f_math(pow)
wrap1f(trunc) wrap1f_math(trunc)
wrap1f(floor) wrap1f_math(floor)
wrap1f(ceil) wrap1f_math(ceil)
wrap2f(fmod) wrap2f_math(fmod)
wrap1s(getEnv) wrap1s_os(getEnv)
wrap1s(existsEnv) wrap1s_os(existsEnv)
wrap1s(dirExists) wrap1s_os(dirExists)
wrap1s(fileExists) wrap1s_os(fileExists)
wrap2svoid(writeFile) wrap2svoid_system(writeFile)
wrap1s_system(readFile)
systemop getCurrentExceptionMsg systemop getCurrentExceptionMsg
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))

View file

@ -36,6 +36,7 @@ type
wColon, wColonColon, wEquals, wDot, wDotDot, wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus, wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks, wMagic, wThread, wFinal, wProfiler, wObjChecks,
wIntDefine, wStrDefine,
wDestroy, wDestroy,
@ -121,7 +122,7 @@ const
":", "::", "=", ".", "..", ":", "::", "=", ".", "..",
"*", "-", "*", "-",
"magic", "thread", "final", "profiler", "objchecks", "magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine",
"destroy", "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.exe = "mips-openwrt-linux-gcc"
mips.linux.gcc.linkerexe = "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/core"
path="$lib/deprecated/pure" path="$lib/deprecated/pure"
path="$lib/pure/collections" path="$lib/pure/collections"
@ -44,6 +40,11 @@ path="$lib/pure"
@if nimbabel: @if nimbabel:
nimblepath="$home/.nimble/pkgs/" nimblepath="$home/.nimble/pkgs/"
@if not windows:
nimblepath="/opt/nimble/pkgs/"
@else:
# TODO:
@end
@end @end
@if release or quick: @if release or quick:
@ -163,10 +164,5 @@ vcc.options.always = "/nologo"
vcc.options.speed = "/O2 /arch:SSE2" vcc.options.speed = "/O2 /arch:SSE2"
vcc.options.size = "/O1" 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: # Configuration for the Tiny C Compiler:
tcc.options.always = "-w" tcc.options.always = "-w"

View file

@ -1,5 +1,5 @@
# This is the config file for the documentation generator. # 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 # 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 # 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-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=="); 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; } margin-bottom: -5px; }
div.pragma {
display: none;
}
span.pragmabegin {
cursor: pointer;
}
span.pragmaend {
cursor: pointer;
}
</style> </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> </head>
<body> <body onload="main()">
<div class="document" id="documentId"> <div class="document" id="documentId">
<div class="container"> <div class="container">
<h1 class="title">$title</h1> <h1 class="title">$title</h1>

View file

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

View file

@ -33,7 +33,7 @@ contains:
of nnkIdent: of nnkIdent:
ident: NimIdent ## the identifier ident: NimIdent ## the identifier
of nnkSym: of nnkSym:
symbol: NimSymbol ## the symbol (after symbol lookup phase) symbol: NimSym ## the symbol (after symbol lookup phase)
else: else:
sons: seq[NimNode] ## the node's sons (or children) 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 `importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
*generic* way of making backend symbols available in Nim and is available *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 in all the target backends (JavaScript too). The C++ or Objective-C backends
have their respective `ImportCpp <nimc.html#importcpp-pragma>`_ and have their respective `ImportCpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
`ImportObjC <nimc.html#importobjc-pragma>`_ pragmas to call methods from `ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ pragmas to call methods from
classes. classes.
Whenever you use any of these pragmas you need to integrate native code into 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 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 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 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 Custom data types

View file

@ -11,7 +11,9 @@ Arguments:
arguments are passed to the program being run (if --run option is selected) arguments are passed to the program being run (if --run option is selected)
Options: Options:
-p, --path:PATH add path to search paths -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 -u, --undef:SYMBOL undefine a conditional symbol
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off --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 available parameters depend on the invoked filter. Before version 0.12.0 of
the language ``#!`` was used instead 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 Pipe operator
============= =============
@ -41,9 +45,6 @@ Filters can be combined with the ``|`` pipe operator::
Available filters Available filters
================= =================
**Hint:** With ``--verbosity:2`` (or higher) Nim lists the processed code
after each filter application.
Replace filter Replace filter
-------------- --------------

View file

@ -56,7 +56,7 @@ file as well). With this switch the GC supports the following operations:
.. code-block:: nim .. code-block:: nim
proc GC_setMaxPause*(MaxPauseInUs: int) 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. 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 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 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 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 These procs provide a "best effort" realtime guarantee; in particular the
cycle collector is not aware of deadlines yet. Deactivate it to get more cycle collector is not aware of deadlines yet. Deactivate it to get more

View file

@ -97,9 +97,16 @@ String handling
case of a string, splitting a string into substrings, searching for case of a string, splitting a string into substrings, searching for
substrings, replacing substrings. 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>`_ * `parseutils <parseutils.html>`_
This module contains helpers for parsing tokens, numbers, identifiers, etc. 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>`_ * `strtabs <strtabs.html>`_
The ``strtabs`` module implements an efficient hash table that is a mapping The ``strtabs`` module implements an efficient hash table that is a mapping
from strings to strings. Supports a case-sensitive, case-insensitive and from strings to strings. Supports a case-sensitive, case-insensitive and
@ -199,6 +206,9 @@ Math libraries
* `mersenne <mersenne.html>`_ * `mersenne <mersenne.html>`_
Mersenne twister random number generator. Mersenne twister random number generator.
* `random <random.html>`_
Fast and tiny random number generator.
* `stats <stats.html>`_ * `stats <stats.html>`_
Statistical analysis Statistical analysis
@ -440,6 +450,10 @@ Regular expressions
This module contains procedures and operators for handling regular This module contains procedures and operators for handling regular
expressions. The current implementation uses PCRE. expressions. The current implementation uses PCRE.
* `nre <nre.html>`_
Another implementation of procedures for using regular expressions. Also uses
PCRE.
Database support Database support
---------------- ----------------

View file

@ -155,4 +155,4 @@ Exception hierarchy
The exception tree is defined in the `system <system.html>`_ module: 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:: .. code-block::
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.} 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 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 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 Exportc pragma
@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
.. code-block:: Nim .. code-block:: Nim
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.} 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 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 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".} = proc p(s: string) {.extern: "prefix$1".} =
echo s 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 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 default parameters are still applied in the provided block, it's also possible
to encode usage protocols that do not reveal implementation details. 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 Much like generics, concepts are instantiated exactly
once for each tested type and any static code included within them is also once for each tested type and any static code included within them is also
executed once. executed once.
@ -303,7 +293,7 @@ definition):
var var
lastId = 0 lastId = 0
template genId*: expr = template genId*: untyped =
bind lastId bind lastId
inc(lastId) inc(lastId)
lastId lastId

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