Merge remote-tracking branch 'origin/devel' into initallocator-fix
This commit is contained in:
commit
db2f96daba
434 changed files with 22365 additions and 6316 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -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)
|
||||||
|
.*/
|
||||||
|
~*
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1668,10 +1699,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||||
of mInc, mDec:
|
of mInc, mDec:
|
||||||
const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
|
const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
|
||||||
const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
|
const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
|
||||||
"$# = #subInt64($#, $#);$n"]
|
"$# = #subInt64($#, $#);$n"]
|
||||||
const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
|
const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
|
||||||
"$# = #subInt($#, $#);$n"]
|
"$# = #subInt($#, $#);$n"]
|
||||||
let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
|
let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
|
||||||
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
|
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
|
||||||
|
|
@ -1712,6 +1743,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mNew: genNew(p, e)
|
of 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" &
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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" %
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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':
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
81
compiler/debuginfo.nim
Normal 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)
|
||||||
|
|
@ -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
|
||||||
|
|
@ -311,7 +355,7 @@ proc docstringSummary(rstText: string): string =
|
||||||
## Also, we hope to not break the rst, but maybe we do. If there is any
|
## Also, we hope to not break the rst, but maybe we do. If there is any
|
||||||
## trimming done, an ellipsis unicode char is added.
|
## trimming done, an ellipsis unicode char is added.
|
||||||
const maxDocstringChars = 100
|
const maxDocstringChars = 100
|
||||||
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
|
assert(rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
|
||||||
result = rstText.substr(2).strip
|
result = rstText.substr(2).strip
|
||||||
var pos = result.find('\L')
|
var pos = result.find('\L')
|
||||||
if pos > 0:
|
if pos > 0:
|
||||||
|
|
@ -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*() =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 & ')')
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
56
compiler/packagehandling.nim
Normal file
56
compiler/packagehandling.nim
Normal 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
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ proc toStrMaxPrecision*(f: BiggestFloat): string =
|
||||||
if f > 0.0: result = "INF"
|
if f > 0.0: result = "INF"
|
||||||
else: result = "-INF"
|
else: result = "-INF"
|
||||||
else:
|
else:
|
||||||
var buf: array [0..80, char]
|
var buf: array[0..80, char]
|
||||||
c_sprintf(buf, "%#.16e", f)
|
c_sprintf(buf, "%#.16e", f)
|
||||||
result = $buf
|
result = $buf
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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]))
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
----------------
|
----------------
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue