mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 09:24:36 +00:00
Merge remote-tracking branch 'origin/devel' into initallocator-fix
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -10,6 +10,7 @@ nimcache/
|
||||
*.dylib
|
||||
*.zip
|
||||
*.iss
|
||||
*.log
|
||||
|
||||
mapping.txt
|
||||
tags
|
||||
@@ -42,3 +43,7 @@ xcuserdata/
|
||||
/testresults.json
|
||||
testament.db
|
||||
/csources
|
||||
|
||||
# Private directories and files (IDEs)
|
||||
.*/
|
||||
~*
|
||||
|
||||
@@ -10,7 +10,7 @@ addons:
|
||||
- libgc-dev
|
||||
before_script:
|
||||
- set -e
|
||||
- wget http://flatassembler.net/fasm-1.71.39.tgz
|
||||
- wget http://nim-lang.org/download/fasm-1.71.39.tgz
|
||||
- tar xvf fasm-1.71.39.tgz
|
||||
- git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
- cd csources
|
||||
@@ -23,6 +23,7 @@ script:
|
||||
- ./koch boot
|
||||
- ./koch boot -d:release
|
||||
- nim e install_nimble.nims
|
||||
- nim e tests/test_nimscript.nims
|
||||
- nimble update
|
||||
- nimble install zip
|
||||
- nimble install opengl
|
||||
|
||||
@@ -18,5 +18,3 @@ set +x
|
||||
|
||||
echo
|
||||
echo 'Install Nim using "./install.sh <dir>" or "sudo ./install.sh <dir>".'
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Package]
|
||||
name = "compiler"
|
||||
version = "0.13.0"
|
||||
version = "0.14.3"
|
||||
author = "Andreas Rumpf"
|
||||
description = "Compiler package providing the compiler sources as a library."
|
||||
license = "MIT"
|
||||
@@ -8,4 +8,4 @@ license = "MIT"
|
||||
InstallDirs = "doc, compiler"
|
||||
|
||||
[Deps]
|
||||
Requires: "nim >= 0.12.0"
|
||||
Requires: "nim >= 0.13.0"
|
||||
|
||||
@@ -271,13 +271,14 @@ type
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
const
|
||||
sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section
|
||||
sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
|
||||
sfNoInit* = sfMainModule # don't generate code to init the variable
|
||||
|
||||
sfImmediate* = sfDeadCodeElim
|
||||
# macro or template is immediately expanded
|
||||
# without considering any possible overloads
|
||||
sfAllUntyped* = sfVolatile # macro or template is immediately expanded \
|
||||
# in a generic context
|
||||
|
||||
sfDirty* = sfPure
|
||||
# template is not hygienic (old styled template)
|
||||
@@ -395,6 +396,9 @@ type
|
||||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
tyVoid #\
|
||||
# now different from tyEmpty, hurray!
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
@@ -528,8 +532,6 @@ const
|
||||
tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
|
||||
# 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
|
||||
# deprecated and this mess can be cleaned up.
|
||||
tfVoid* = tfVarargs # for historical reasons we conflated 'void' with
|
||||
# 'empty' ('@[]' has the type 'seq[empty]').
|
||||
tfReturnsNew* = tfInheritable
|
||||
skError* = skUnknown
|
||||
|
||||
@@ -544,7 +546,7 @@ type
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mInc, mDec, mOrd,
|
||||
mNew, mNewFinalize, mNewSeq,
|
||||
mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
|
||||
mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
|
||||
mXLenStr, mXLenSeq,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
@@ -563,8 +565,8 @@ type
|
||||
mEqEnum, mLeEnum, mLtEnum,
|
||||
mEqCh, mLeCh, mLtCh,
|
||||
mEqB, mLeB, mLtB,
|
||||
mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mEqCString,
|
||||
mXor, mEqProc,
|
||||
mEqRef, mEqUntracedRef, mLePtr, mLtPtr,
|
||||
mXor, mEqCString, mEqProc,
|
||||
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
|
||||
@@ -590,6 +592,7 @@ type
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
mOrdinal,
|
||||
mInt, mInt8, mInt16, mInt32, mInt64,
|
||||
mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
|
||||
@@ -609,7 +612,7 @@ type
|
||||
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
|
||||
mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo, mNGenSym,
|
||||
mNimvm
|
||||
mNimvm, mIntDefine, mStrDefine
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
@@ -769,7 +772,7 @@ type
|
||||
procInstCache*: seq[PInstantiation]
|
||||
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
|
||||
#scope*: PScope # the scope where the proc was defined
|
||||
of skModule:
|
||||
of skModule, skPackage:
|
||||
# modules keep track of the generic symbols they use from other modules.
|
||||
# this is because in incremental compilation, when a module is about to
|
||||
# be replaced with a newer version, we must decrement the usage count
|
||||
@@ -848,6 +851,7 @@ type
|
||||
# see instantiateDestructor in semdestruct.nim
|
||||
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||
assignment*: PSym # overriden '=' operator
|
||||
methods*: seq[(int,PSym)] # attached methods
|
||||
size*: BiggestInt # the size of the type in bytes
|
||||
# -1 means that the size is unkwown
|
||||
align*: int16 # the type's alignment requirements
|
||||
@@ -938,7 +942,7 @@ const
|
||||
genericParamsPos* = 2
|
||||
paramsPos* = 3
|
||||
pragmasPos* = 4
|
||||
optimizedCodePos* = 5 # will be used for exception tracking
|
||||
miscPos* = 5 # used for undocumented and hacky stuff
|
||||
bodyPos* = 6 # position of body; use rodread.getBody() instead!
|
||||
resultPos* = 7
|
||||
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
|
||||
@@ -961,6 +965,8 @@ const
|
||||
skMethod, skConverter}
|
||||
|
||||
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
|
||||
var
|
||||
gMainPackageId*: int
|
||||
|
||||
proc isCallExpr*(n: PNode): bool =
|
||||
result = n.kind in nkCallKinds
|
||||
@@ -984,12 +990,12 @@ proc add*(father, son: PNode) =
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
template `-|`*(b, s: expr): expr =
|
||||
template `-|`*(b, s: untyped): untyped =
|
||||
(if b >= 0: b else: s.len + b)
|
||||
|
||||
# son access operators with support for negative indices
|
||||
template `{}`*(n: PNode, i: int): expr = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode) =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
@@ -1584,7 +1590,7 @@ proc isAtom*(n: PNode): bool {.inline.} =
|
||||
|
||||
proc isEmptyType*(t: PType): bool {.inline.} =
|
||||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||
result = t == nil or t.kind in {tyVoid, tyStmt}
|
||||
|
||||
proc makeStmtList*(n: PNode): PNode =
|
||||
if n.kind == nkStmtList:
|
||||
|
||||
@@ -124,7 +124,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
|
||||
result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
|
||||
of tyArray, tyArrayConstr:
|
||||
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
|
||||
else:
|
||||
else:
|
||||
internalError("openArrayLoc: " & typeToString(a.t))
|
||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||
|
||||
@@ -260,7 +260,11 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i])
|
||||
if tfVarargs notin typ.flags:
|
||||
localError(ri.info, "wrong argument count")
|
||||
result = nil
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i])
|
||||
|
||||
discard """
|
||||
Dot call syntax in C++
|
||||
|
||||
@@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope =
|
||||
|
||||
proc getStrLit(m: BModule, s: string): Rope =
|
||||
discard cgsym(m, "TGenericSeq")
|
||||
result = "TMP" & rope(backendId())
|
||||
result = getTempName(m)
|
||||
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
|
||||
[result, makeCString(s), rope(len(s))])
|
||||
|
||||
@@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
of nkNilLit:
|
||||
let t = skipTypes(ty, abstractVarRange)
|
||||
if t.kind == tyProc and t.callConv == ccClosure:
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
result = "TMP" & rope(id)
|
||||
if id == gBackendId:
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
result = p.module.tmpBase & rope(id)
|
||||
if id == p.module.labels:
|
||||
# not found in cache:
|
||||
inc(gBackendId)
|
||||
inc(p.module.labels)
|
||||
addf(p.module.s[cfsData],
|
||||
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
|
||||
[getTypeDesc(p.module, t), result])
|
||||
@@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
if n.strVal.isNil:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
|
||||
elif skipTypes(ty, abstractVarRange).kind == tyString:
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
if id == gBackendId:
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
if id == p.module.labels:
|
||||
# string literal not found in the cache:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||
[getStrLit(p.module, n.strVal)])
|
||||
else:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
|
||||
[p.module.tmpBase, rope(id)])
|
||||
else:
|
||||
result = makeCString(n.strVal)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
@@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope =
|
||||
var size = int(getSize(n.typ))
|
||||
toBitSet(n, cs)
|
||||
if size > 8:
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
result = "TMP" & rope(id)
|
||||
if id == gBackendId:
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
result = p.module.tmpBase & rope(id)
|
||||
if id == p.module.labels:
|
||||
# not found in cache:
|
||||
inc(gBackendId)
|
||||
inc(p.module.labels)
|
||||
addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
|
||||
else:
|
||||
@@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
|
||||
var size = getSize(t)
|
||||
let storage = if size < platform.intSize: rope("NI")
|
||||
else: getTypeDesc(p.module, t)
|
||||
result = getTempName()
|
||||
result = getTempName(p.module)
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
|
||||
lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
|
||||
if size < platform.intSize or t.kind in {tyRange, tyEnum}:
|
||||
@@ -591,7 +592,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
"($1 == $2)", # EqPtr
|
||||
"($1 <= $2)", # LePtr
|
||||
"($1 < $2)", # LtPtr
|
||||
"($1 == $2)", # EqCString
|
||||
"($1 != $2)"] # Xor
|
||||
var
|
||||
a, b: TLoc
|
||||
@@ -612,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
||||
assert(e.sons[2].typ != nil)
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
if a.t.callConv == ccClosure:
|
||||
if a.t.skipTypes(abstractInst).callConv == ccClosure:
|
||||
putIntoDest(p, d, e.typ,
|
||||
"($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
|
||||
else:
|
||||
@@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||
#if e[0].kind != nkBracketExpr:
|
||||
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
|
||||
expr(p, e.sons[0], d)
|
||||
if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
|
||||
d.s = OnHeap
|
||||
else:
|
||||
var a: TLoc
|
||||
let typ = skipTypes(e.sons[0].typ, abstractInst)
|
||||
@@ -802,9 +804,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
|
||||
v.r.add(d.loc.r)
|
||||
genInExprAux(p, it, u, v, test)
|
||||
let id = nodeTableTestOrSet(p.module.dataCache,
|
||||
newStrNode(nkStrLit, field.name.s), gBackendId)
|
||||
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
|
||||
else: "TMP" & rope(id)
|
||||
newStrNode(nkStrLit, field.name.s), p.module.labels)
|
||||
let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
|
||||
else: p.module.tmpBase & rope(id)
|
||||
if op.magic == mNot:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
||||
@@ -1141,7 +1143,35 @@ proc genNewSeq(p: BProc, e: PNode) =
|
||||
genNewSeqAux(p, a, b.rdLoc)
|
||||
gcUsage(e)
|
||||
|
||||
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
let seqtype = skipTypes(e.typ, abstractVarRange)
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
genTypeInfo(p.module, seqtype), a.rdLoc]))
|
||||
gcUsage(e)
|
||||
|
||||
proc genConstExpr(p: BProc, n: PNode): Rope
|
||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
|
||||
var t = getUniqueType(n.typ)
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
|
||||
if id == p.module.labels:
|
||||
# expression not found in the cache:
|
||||
inc(p.module.labels)
|
||||
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
if handleConstExpr(p, e, d): return
|
||||
#echo rendertree e, " ", e.isDeepConstExpr
|
||||
var tmp: TLoc
|
||||
var t = e.typ.skipTypes(abstractInst)
|
||||
getTemp(p, t, tmp)
|
||||
@@ -1235,7 +1265,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
|
||||
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
|
||||
# have to call it here first:
|
||||
let ti = genTypeInfo(p.module, dest)
|
||||
if tfFinal in dest.flags or (p.module.objHasKidsValid and
|
||||
if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
|
||||
tfObjHasKids notin dest.flags):
|
||||
result = "$1.m_type == $2" % [a, ti]
|
||||
else:
|
||||
@@ -1293,7 +1323,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.s)
|
||||
of tyEnum, tyOrdinal:
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprEnum($1, $2)", [
|
||||
ropecg(p.module, "#reprEnum((NI)$1, $2)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyString:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s)
|
||||
@@ -1320,7 +1350,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprAny($1, $2)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyEmpty:
|
||||
of tyEmpty, tyVoid:
|
||||
localError(e.info, "'repr' doesn't support 'void' type")
|
||||
else:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
|
||||
@@ -1558,11 +1588,12 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
|
||||
|
||||
proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
const floatTypes = {tyFloat..tyFloat128}
|
||||
const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject,
|
||||
tyArray, tyArrayConstr}
|
||||
let
|
||||
destt = skipTypes(e.typ, abstractRange)
|
||||
srct = skipTypes(e.sons[1].typ, abstractRange)
|
||||
if destt.kind in floatTypes or srct.kind in floatTypes:
|
||||
if destt.kind in ValueTypes or srct.kind in ValueTypes:
|
||||
# 'cast' and some float type involved? --> use a union.
|
||||
inc(p.labels)
|
||||
var lbl = p.labels.rope
|
||||
@@ -1668,10 +1699,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||
of mInc, mDec:
|
||||
const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
|
||||
const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
|
||||
const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
|
||||
const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
|
||||
"$# = #subInt64($#, $#);$n"]
|
||||
const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
|
||||
const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
|
||||
"$# = #subInt($#, $#);$n"]
|
||||
let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
|
||||
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
|
||||
@@ -1712,6 +1743,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mNew: genNew(p, e)
|
||||
of mNewFinalize: genNewFinalize(p, e)
|
||||
of mNewSeq: genNewSeq(p, e)
|
||||
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
|
||||
of mSizeOf:
|
||||
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
|
||||
putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
|
||||
@@ -1754,25 +1786,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
initLocExpr(p, x, a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
genDeepCopy(p, a, b)
|
||||
of mDotDot: genCall(p, e, d)
|
||||
of mDotDot, mEqCString: genCall(p, e, d)
|
||||
else: internalError(e.info, "genMagicExpr: " & $op)
|
||||
|
||||
proc genConstExpr(p: BProc, n: PNode): Rope
|
||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
|
||||
var t = getUniqueType(n.typ)
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
fillLoc(d, locData, t, "TMP" & rope(id), OnStatic)
|
||||
if id == gBackendId:
|
||||
# expression not found in the cache:
|
||||
inc(gBackendId)
|
||||
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
# example: { a..b, c, d, e, f..g }
|
||||
# we have to emit an expression of the form:
|
||||
@@ -1856,10 +1872,16 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||
initLocExpr(p, n.sons[1], b)
|
||||
if n.sons[0].skipConv.kind == nkClosure:
|
||||
internalError(n.info, "closure to closure created")
|
||||
getTemp(p, n.typ, tmp)
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
tmp.rdLoc, a.rdLoc, b.rdLoc)
|
||||
putLocIntoDest(p, d, tmp)
|
||||
# tasyncawait.nim breaks with this optimization:
|
||||
when false:
|
||||
if d.k != locNone:
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
d.rdLoc, a.rdLoc, b.rdLoc)
|
||||
else:
|
||||
getTemp(p, n.typ, tmp)
|
||||
linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
|
||||
tmp.rdLoc, a.rdLoc, b.rdLoc)
|
||||
putLocIntoDest(p, d, tmp)
|
||||
|
||||
proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var arr: TLoc
|
||||
@@ -1947,12 +1969,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
var t = getUniqueType(n.typ)
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
var tmp = "TMP" & rope(id)
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
let tmp = p.module.tmpBase & rope(id)
|
||||
|
||||
if id == gBackendId:
|
||||
if id == p.module.labels:
|
||||
# expression not found in the cache:
|
||||
inc(gBackendId)
|
||||
inc(p.module.labels)
|
||||
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
||||
|
||||
@@ -1960,6 +1982,10 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
fillLoc(d, locData, t, tmp, OnStatic)
|
||||
else:
|
||||
putDataIntoDest(p, d, t, tmp)
|
||||
# This fixes bug #4551, but we really need better dataflow
|
||||
# analysis to make this 100% safe.
|
||||
if t.kind notin {tySequence, tyString}:
|
||||
d.s = OnStatic
|
||||
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
case n.kind
|
||||
@@ -1985,10 +2011,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
internalError(n.info, "expr: proc not init " & sym.name.s)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skConst:
|
||||
if sfFakeConst in sym.flags:
|
||||
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
elif isSimpleConst(sym.typ):
|
||||
if isSimpleConst(sym.typ):
|
||||
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic)
|
||||
else:
|
||||
genComplexConst(p, sym, d)
|
||||
@@ -2160,7 +2183,8 @@ proc genConstSimpleList(p: BProc, n: PNode): Rope =
|
||||
result = rope("{")
|
||||
for i in countup(ord(n.kind == nkObjConstr), length - 2):
|
||||
addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
|
||||
if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
|
||||
if length > ord(n.kind == nkObjConstr):
|
||||
add(result, genNamedConstExpr(p, n.sons[length - 1]))
|
||||
addf(result, "}$n", [])
|
||||
|
||||
proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
|
||||
@@ -2174,8 +2198,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
|
||||
data.add("}")
|
||||
data.add("}")
|
||||
|
||||
inc(gBackendId)
|
||||
result = "CNSTSEQ" & gBackendId.rope
|
||||
result = getTempName(p.module)
|
||||
|
||||
appcg(p.module, cfsData,
|
||||
"NIM_CONST struct {$n" &
|
||||
|
||||
@@ -107,13 +107,13 @@ proc genMergeInfo*(m: BModule): Rope =
|
||||
writeIntSet(m.typeInfoMarker, s)
|
||||
s.add("labels:")
|
||||
encodeVInt(m.labels, s)
|
||||
s.add(" hasframe:")
|
||||
encodeVInt(ord(m.frameDeclared), s)
|
||||
s.add(" flags:")
|
||||
encodeVInt(cast[int](m.flags), s)
|
||||
s.add(tnl)
|
||||
s.add("*/")
|
||||
result = s.rope
|
||||
|
||||
template `^`(pos: int): expr = L.buf[pos]
|
||||
template `^`(pos: int): untyped = L.buf[pos]
|
||||
|
||||
proc skipWhite(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
@@ -222,13 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||
of "declared": readIntSet(L, m.declaredThings)
|
||||
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
||||
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
||||
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||
of "flags":
|
||||
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
|
||||
else: internalError("ccgmerge: unknown key: " & k)
|
||||
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
template withCFile(cfilename: string, body: stmt) {.immediate.} =
|
||||
template withCFile(cfilename: string, body: untyped) =
|
||||
var s = llStreamOpen(cfilename, fmRead)
|
||||
if s == nil: return
|
||||
var L {.inject.}: TBaseLexer
|
||||
|
||||
@@ -16,7 +16,7 @@ const
|
||||
# above X strings a hash-switch for strings is generated
|
||||
|
||||
proc registerGcRoot(p: BProc, v: PSym) =
|
||||
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2} and
|
||||
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
# we register a specialized marked proc here; this has the advantage
|
||||
# that it works out of the box for thread local storage then :-)
|
||||
@@ -136,7 +136,7 @@ proc exprBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
expr(p, n, d)
|
||||
endBlock(p)
|
||||
|
||||
template preserveBreakIdx(body: stmt): stmt {.immediate.} =
|
||||
template preserveBreakIdx(body: untyped): untyped =
|
||||
var oldBreakIdx = p.breakIdx
|
||||
body
|
||||
p.breakIdx = oldBreakIdx
|
||||
@@ -269,8 +269,6 @@ proc genConstStmt(p: BProc, t: PNode) =
|
||||
if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
|
||||
var c = it.sons[0].sym
|
||||
if c.typ.containsCompileTimeOnly: continue
|
||||
if sfFakeConst in c.flags:
|
||||
genSingleVar(p, it)
|
||||
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
|
||||
c.ast.len != 0:
|
||||
if not emitLazily(c): requestConstImpl(p, c)
|
||||
@@ -570,7 +568,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
# reraise the last exception:
|
||||
if p.module.compileToCpp:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n")
|
||||
@@ -793,7 +791,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
if not isEmptyType(t.typ) and d.k == locNone:
|
||||
getTemp(p, t.typ, d)
|
||||
genLineDir(p, t)
|
||||
let exc = getTempName()
|
||||
let exc = getTempName(p.module)
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
@@ -886,7 +884,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
getTemp(p, t.typ, d)
|
||||
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName()
|
||||
var safePoint = getTempName(p.module)
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
@@ -961,6 +959,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[i], a)
|
||||
res.add($rdLoc(a))
|
||||
elif sym.kind == skType:
|
||||
res.add($getTypeDesc(p.module, sym.typ))
|
||||
else:
|
||||
var r = sym.loc.r
|
||||
if r == nil:
|
||||
|
||||
@@ -18,7 +18,7 @@ proc emulatedThreadVars(): bool =
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||
if emulatedThreadVars() and not p.threadVarAccessed:
|
||||
p.threadVarAccessed = true
|
||||
p.module.usesThreadVars = true
|
||||
incl p.module.flags, usesThreadVars
|
||||
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
|
||||
add(p.procSec(cpsInit),
|
||||
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
|
||||
@@ -51,7 +51,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
|
||||
addf(m.s[cfsVars], " $1;$n", [s.loc.r])
|
||||
|
||||
proc generateThreadLocalStorage(m: BModule) =
|
||||
if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
|
||||
if nimtv != nil and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
|
||||
for t in items(nimtvDeps): discard getTypeDesc(m, t)
|
||||
addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
|
||||
var c: TTraversalClosure
|
||||
var p = newProc(nil, m)
|
||||
result = getGlobalTempName()
|
||||
result = getTempName(m)
|
||||
|
||||
case reason
|
||||
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
|
||||
@@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
|
||||
var c: TTraversalClosure
|
||||
var p = newProc(nil, m)
|
||||
var sLoc = s.loc.r
|
||||
result = getGlobalTempName()
|
||||
result = getTempName(m)
|
||||
|
||||
if sfThread in s.flags and emulatedThreadVars():
|
||||
accessThreadLocalVar(p, s)
|
||||
@@ -143,7 +143,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
|
||||
|
||||
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
||||
c.p = p
|
||||
let header = "N_NIMCALL(void, $1)()" % [result]
|
||||
let header = "N_NIMCALL(void, $1)(void)" % [result]
|
||||
genTraverseProc(c, sLoc, s.loc.t)
|
||||
|
||||
let generatedProc = "$1 {$n$2$3$4}$n" %
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2016 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
# ------------------------- Name Mangling --------------------------------
|
||||
|
||||
import debuginfo
|
||||
|
||||
proc isKeyword(w: PIdent): bool =
|
||||
# Nim and C++ share some keywords
|
||||
# it's more efficient to test the whole Nim keywords range
|
||||
@@ -23,70 +25,70 @@ proc isKeyword(w: PIdent): bool =
|
||||
proc mangleField(name: PIdent): string =
|
||||
result = mangle(name.s)
|
||||
if isKeyword(name):
|
||||
result[0] = result[0].toUpper # Mangling makes everything lowercase,
|
||||
# but some identifiers are C keywords
|
||||
result[0] = result[0].toUpperAscii
|
||||
# Mangling makes everything lowercase,
|
||||
# but some identifiers are C keywords
|
||||
|
||||
proc hashOwner(s: PSym): FilenameHash =
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
let p = m.owner
|
||||
assert p.kind == skPackage
|
||||
result = gDebugInfo.register(p.name.s, m.name.s)
|
||||
|
||||
proc mangleName(s: PSym): Rope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
when oKeepVariableNames:
|
||||
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
||||
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
|
||||
not isKeyword(s.name)
|
||||
# XXX: This is still very experimental
|
||||
#
|
||||
# Even with all these inefficient checks, the bootstrap
|
||||
# time is actually improved. This is probably because so many
|
||||
# rope concatenations are now eliminated.
|
||||
#
|
||||
# Future notes:
|
||||
# sfFromGeneric seems to be needed in order to avoid multiple
|
||||
# definitions of certain variables generated in transf with
|
||||
# names such as:
|
||||
# `r`, `res`
|
||||
# I need to study where these come from.
|
||||
#
|
||||
# about sfShadowed:
|
||||
# consider the following Nim code:
|
||||
# var x = 10
|
||||
# block:
|
||||
# var x = something(x)
|
||||
# The generated C code will be:
|
||||
# NI x;
|
||||
# x = 10;
|
||||
# {
|
||||
# NI x;
|
||||
# x = something(x); // Oops, x is already shadowed here
|
||||
# }
|
||||
# Right now, we work-around by not keeping the original name
|
||||
# of the shadowed variable, but we can do better - we can
|
||||
# create an alternative reference to it in the outer scope and
|
||||
# use that in the inner scope.
|
||||
#
|
||||
# about isCKeyword:
|
||||
# Nim variable names can be C keywords.
|
||||
# We need to avoid such names in the generated code.
|
||||
# XXX: Study whether mangleName is called just once per variable.
|
||||
# Otherwise, there might be better place to do this.
|
||||
#
|
||||
# about sfGlobal:
|
||||
# This seems to be harder - a top level extern variable from
|
||||
# another modules can have the same name as a local one.
|
||||
# Maybe we should just implement sfShadowed for them too.
|
||||
#
|
||||
# about skForVar:
|
||||
# These are not properly scoped now - we need to add blocks
|
||||
# around for loops in transf
|
||||
if keepOrigName:
|
||||
result = s.name.s.mangle.rope
|
||||
else:
|
||||
add(result, rope(mangle(s.name.s)))
|
||||
add(result, ~"_")
|
||||
add(result, rope(s.id))
|
||||
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
||||
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
|
||||
not isKeyword(s.name)
|
||||
# Even with all these inefficient checks, the bootstrap
|
||||
# time is actually improved. This is probably because so many
|
||||
# rope concatenations are now eliminated.
|
||||
#
|
||||
# sfFromGeneric is needed in order to avoid multiple
|
||||
# definitions of certain variables generated in transf with
|
||||
# names such as:
|
||||
# `r`, `res`
|
||||
# I need to study where these come from.
|
||||
#
|
||||
# about sfShadowed:
|
||||
# consider the following Nim code:
|
||||
# var x = 10
|
||||
# block:
|
||||
# var x = something(x)
|
||||
# The generated C code will be:
|
||||
# NI x;
|
||||
# x = 10;
|
||||
# {
|
||||
# NI x;
|
||||
# x = something(x); // Oops, x is already shadowed here
|
||||
# }
|
||||
# Right now, we work-around by not keeping the original name
|
||||
# of the shadowed variable, but we can do better - we can
|
||||
# create an alternative reference to it in the outer scope and
|
||||
# use that in the inner scope.
|
||||
#
|
||||
# about isCKeyword:
|
||||
# Nim variable names can be C keywords.
|
||||
# We need to avoid such names in the generated code.
|
||||
#
|
||||
# about sfGlobal:
|
||||
# This seems to be harder - a top level extern variable from
|
||||
# another modules can have the same name as a local one.
|
||||
# Maybe we should just implement sfShadowed for them too.
|
||||
#
|
||||
# about skForVar:
|
||||
# These are not properly scoped now - we need to add blocks
|
||||
# around for loops in transf
|
||||
result = s.name.s.mangle.rope
|
||||
if keepOrigName:
|
||||
result.add "0"
|
||||
else:
|
||||
add(result, rope(mangle(s.name.s)))
|
||||
add(result, ~"_")
|
||||
add(result, rope(s.id))
|
||||
add(result, ~"_")
|
||||
add(result, rope(hashOwner(s).BiggestInt))
|
||||
s.loc.r = result
|
||||
|
||||
proc typeName(typ: PType): Rope =
|
||||
@@ -137,6 +139,10 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
var base = skipTypes(typ.lastSon, typedescInst)
|
||||
case base.kind
|
||||
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
|
||||
#of tySet:
|
||||
# if mapSetType(base) == ctArray: result = ctPtrToArray
|
||||
# else: result = ctPtr
|
||||
# XXX for some reason this breaks the pegs module
|
||||
else: result = ctPtr
|
||||
of tyPointer: result = ctPtr
|
||||
of tySequence: result = ctNimSeq
|
||||
@@ -145,11 +151,15 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
of tyCString: result = ctCString
|
||||
of tyInt..tyUInt64:
|
||||
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = mapType(lastSon typ)
|
||||
else: internalError("mapType")
|
||||
else: internalError("mapType")
|
||||
|
||||
proc mapReturnType(typ: PType): TCTypeKind =
|
||||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||
else: result = mapType(typ)
|
||||
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||
#else:
|
||||
result = mapType(typ)
|
||||
|
||||
proc isImportedType(t: PType): bool =
|
||||
result = t.sym != nil and sfImportc in t.sym.flags
|
||||
@@ -196,11 +206,9 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope =
|
||||
# linear search is not necessary anymore:
|
||||
result = Rope(idTableGet(tab, key))
|
||||
|
||||
proc getTempName(): Rope =
|
||||
result = rfmt(nil, "TMP$1", rope(backendId()))
|
||||
|
||||
proc getGlobalTempName(): Rope =
|
||||
result = rfmt(nil, "TMP$1", rope(backendId()))
|
||||
proc getTempName(m: BModule): Rope =
|
||||
result = m.tmpBase & rope(m.labels)
|
||||
inc m.labels
|
||||
|
||||
proc ccgIntroducedPtr(s: PSym): bool =
|
||||
var pt = skipTypes(s.typ, typedescInst)
|
||||
@@ -223,7 +231,7 @@ proc ccgIntroducedPtr(s: PSym): bool =
|
||||
proc fillResult(param: PSym) =
|
||||
fillLoc(param.loc, locParam, param.typ, ~"Result",
|
||||
OnStack)
|
||||
if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
|
||||
if mapReturnType(param.typ) != ctArray and isInvalidReturnType(param.typ):
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
|
||||
@@ -238,22 +246,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
|
||||
"NI", "NI8", "NI16", "NI32", "NI64",
|
||||
"NF", "NF32", "NF64", "NF128",
|
||||
"NU", "NU8", "NU16", "NU32", "NU64",]
|
||||
"NU", "NU8", "NU16", "NU32", "NU64"]
|
||||
case typ.kind
|
||||
of tyPointer:
|
||||
result = typeNameOrLiteral(typ, "void*")
|
||||
of tyEnum:
|
||||
if firstOrd(typ) < 0:
|
||||
result = typeNameOrLiteral(typ, "NI32")
|
||||
else:
|
||||
case int(getSize(typ))
|
||||
of 1: result = typeNameOrLiteral(typ, "NU8")
|
||||
of 2: result = typeNameOrLiteral(typ, "NU16")
|
||||
of 4: result = typeNameOrLiteral(typ, "NI32")
|
||||
of 8: result = typeNameOrLiteral(typ, "NI64")
|
||||
else:
|
||||
internalError(typ.sym.info, "getSimpleTypeDesc: " & $(getSize(typ)))
|
||||
result = nil
|
||||
of tyString:
|
||||
discard cgsym(m, "NimStringDesc")
|
||||
result = typeNameOrLiteral(typ, "NimStringDesc*")
|
||||
@@ -264,6 +260,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||
of tyInt..tyUInt64:
|
||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
||||
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
|
||||
else: internalError("tyStatic for getSimpleTypeDesc")
|
||||
of tyGenericInst:
|
||||
result = getSimpleTypeDesc(m, lastSon typ)
|
||||
else: result = nil
|
||||
|
||||
proc pushType(m: BModule, typ: PType) =
|
||||
@@ -317,7 +318,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||
result = getTypeDescAux(m, t, check)
|
||||
|
||||
proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
|
||||
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray, tyVarargs, tyArrayConstr}:
|
||||
result = OnStack
|
||||
else:
|
||||
result = OnUnknown
|
||||
@@ -326,7 +327,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
if t.sons[0] == nil or isInvalidReturnType(t.sons[0]):
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.sons[0], check)
|
||||
@@ -359,10 +360,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
|
||||
inc(j)
|
||||
arr = arr.sons[0]
|
||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||
if t.sons[0] != nil and isInvalidReturnType(t.sons[0]):
|
||||
var arr = t.sons[0]
|
||||
if params != nil: add(params, ", ")
|
||||
if (mapReturnType(t.sons[0]) != ctArray):
|
||||
if mapReturnType(t.sons[0]) != ctArray:
|
||||
add(params, getTypeDescWeak(m, arr, check))
|
||||
add(params, "*")
|
||||
else:
|
||||
@@ -424,7 +425,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
addf(result, "union{$n$1} $2;$n", [unionBody, uname])
|
||||
of nkSym:
|
||||
field = n.sym
|
||||
if field.typ.kind == tyEmpty: return
|
||||
if field.typ.kind == tyVoid: return
|
||||
#assert(field.ast == nil)
|
||||
sname = mangleRecFieldName(field, rectype)
|
||||
if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
|
||||
@@ -483,7 +484,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||
else:
|
||||
addf(result, " {$n", [name])
|
||||
|
||||
var desc = getRecordFields(m, typ, check)
|
||||
let desc = getRecordFields(m, typ, check)
|
||||
if desc == nil and not hasField:
|
||||
addf(result, "char dummy;$n", [])
|
||||
else:
|
||||
@@ -536,8 +537,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
result = getTypePre(m, t)
|
||||
if result != nil: return
|
||||
if containsOrIncl(check, t.id):
|
||||
if isImportedCppType(typ) or isImportedCppType(t): return
|
||||
internalError("cannot generate C type for: " & typeToString(typ))
|
||||
if not (isImportedCppType(typ) or isImportedCppType(t)):
|
||||
internalError("cannot generate C type for: " & typeToString(typ))
|
||||
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
||||
# but determining when this needs to be done is hard. We should split
|
||||
# C type generation into an analysis and a code generation phase somehow.
|
||||
@@ -576,8 +577,37 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
result = getTypeDescAux(m, et, check) & star
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = getTypeDescAux(m, t.sons[0], check) & "*"
|
||||
result = getTypeDescWeak(m, t.sons[0], check) & "*"
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyRange, tyEnum:
|
||||
let t = if t.kind == tyRange: t.lastSon else: t
|
||||
result = cacheGetType(m.typeCache, t)
|
||||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not (isImportedCppType(t) or
|
||||
(sfImportc in t.sym.flags and t.sym.magic == mNone)):
|
||||
idTablePut(m.typeCache, t, result)
|
||||
var size: int
|
||||
if firstOrd(t) < 0:
|
||||
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
|
||||
size = 4
|
||||
else:
|
||||
size = int(getSize(t))
|
||||
case size
|
||||
of 1: addf(m.s[cfsTypes], "typedef NU8 $1;$n", [result])
|
||||
of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
|
||||
of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
|
||||
of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
|
||||
else: internalError(t.sym.info, "getTypeDescAux: enum")
|
||||
let owner = hashOwner(t.sym)
|
||||
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
|
||||
var vals: seq[(string, int)] = @[]
|
||||
for i in countup(0, t.n.len - 1):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
let field = t.n.sons[i].sym
|
||||
vals.add((field.name.s, field.position.int))
|
||||
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
|
||||
name: t.sym.name.s, values: vals))
|
||||
of tyProc:
|
||||
result = getTypeName(t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
@@ -642,7 +672,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
chunkStart = i
|
||||
|
||||
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
|
||||
if typeInSlot == nil or typeInSlot.kind == tyEmpty:
|
||||
if typeInSlot == nil or typeInSlot.kind == tyVoid:
|
||||
result.add(~"void")
|
||||
else:
|
||||
result.add getTypeDescAux(m, typeInSlot, check)
|
||||
@@ -654,7 +684,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
else:
|
||||
result = cppName & "<"
|
||||
for i in 1 .. typ.len-2:
|
||||
if i > 1: result.add(", ")
|
||||
if i > 1: result.add(" COMMA ")
|
||||
result.add(getTypeDescAux(m, typ.sons[i], check))
|
||||
result.add("> ")
|
||||
# always call for sideeffects:
|
||||
@@ -673,16 +703,13 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
else: getTupleDesc(m, t, result, check)
|
||||
if not isImportedType(t): add(m.s[cfsTypes], recdesc)
|
||||
of tySet:
|
||||
case int(getSize(t))
|
||||
of 1: result = rope("NU8")
|
||||
of 2: result = rope("NU16")
|
||||
of 4: result = rope("NU32")
|
||||
of 8: result = rope("NU64")
|
||||
else:
|
||||
result = getTypeName(t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
result = getTypeName(t.lastSon) & "Set"
|
||||
idTablePut(m.typeCache, t, result)
|
||||
if not isImportedType(t):
|
||||
let s = int(getSize(t))
|
||||
case s
|
||||
of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
|
||||
else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
[result, rope(getSize(t))])
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
|
||||
tyIter, tyTypeDesc:
|
||||
@@ -704,7 +731,7 @@ type
|
||||
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
|
||||
assert t.kind == tyProc
|
||||
var check = initIntSet()
|
||||
result = getTempName()
|
||||
result = getTempName(m)
|
||||
var rettype, desc: Rope
|
||||
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
|
||||
if not isImportedType(t):
|
||||
@@ -739,7 +766,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope =
|
||||
genCLineDir(result, prc.info)
|
||||
# using static is needed for inline procs
|
||||
if lfExportLib in prc.loc.flags:
|
||||
if m.isHeaderFile:
|
||||
if isHeaderFile in m.flags:
|
||||
result.add "N_LIB_IMPORT "
|
||||
else:
|
||||
result.add "N_LIB_EXPORT "
|
||||
@@ -819,7 +846,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
|
||||
if L == 1:
|
||||
genObjectFields(m, typ, n.sons[0], expr)
|
||||
elif L > 0:
|
||||
var tmp = getTempName()
|
||||
var tmp = getTempName(m)
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
|
||||
for i in countup(0, L-1):
|
||||
var tmp2 = getNimNode(m)
|
||||
@@ -891,7 +918,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
|
||||
var expr = getNimNode(m)
|
||||
var length = sonsLen(typ)
|
||||
if length > 0:
|
||||
var tmp = getTempName()
|
||||
var tmp = getTempName(m)
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
|
||||
for i in countup(0, length - 1):
|
||||
var a = typ.sons[i]
|
||||
@@ -915,7 +942,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
|
||||
# anyway. We generate a cstring array and a loop over it. Exceptional
|
||||
# positions will be reset after the loop.
|
||||
genTypeInfoAux(m, typ, typ, name)
|
||||
var nodePtrs = getTempName()
|
||||
var nodePtrs = getTempName(m)
|
||||
var length = sonsLen(typ.n)
|
||||
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
||||
[nodePtrs, rope(length)])
|
||||
@@ -935,8 +962,8 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
|
||||
if field.position != i or tfEnumHasHoles in typ.flags:
|
||||
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
|
||||
hasHoles = true
|
||||
var enumArray = getTempName()
|
||||
var counter = getTempName()
|
||||
var enumArray = getTempName(m)
|
||||
var counter = getTempName(m)
|
||||
addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
|
||||
addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
|
||||
[enumArray, rope(length), enumNames])
|
||||
@@ -1004,9 +1031,12 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||
[result, rope(typeToString(t))])
|
||||
return "(&".rope & result & ")".rope
|
||||
case t.kind
|
||||
of tyEmpty: result = rope"0"
|
||||
of tyEmpty, tyVoid: result = rope"0"
|
||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
of tyStatic:
|
||||
if t.n != nil: result = genTypeInfo(m, lastSon t)
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
|
||||
@@ -93,7 +93,7 @@ proc getUniqueType*(key: PType): PType =
|
||||
# produced instead of ``NI``.
|
||||
result = key
|
||||
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
||||
tyCString, tyNone, tyBigNum:
|
||||
tyCString, tyNone, tyBigNum, tyVoid:
|
||||
result = gCanonicalTypes[k]
|
||||
if result == nil:
|
||||
gCanonicalTypes[k] = key
|
||||
@@ -188,7 +188,7 @@ proc mangle*(name: string): string =
|
||||
let c = name[i]
|
||||
case c
|
||||
of 'A'..'Z':
|
||||
add(result, c.toLower)
|
||||
add(result, c.toLowerAscii)
|
||||
of '_':
|
||||
discard
|
||||
of 'a'..'z', '0'..'9':
|
||||
|
||||
@@ -64,8 +64,8 @@ proc isSimpleConst(typ: PType): bool =
|
||||
(t.kind == tyProc and t.callConv == ccClosure)
|
||||
|
||||
proc useStringh(m: BModule) =
|
||||
if not m.includesStringh:
|
||||
m.includesStringh = true
|
||||
if includesStringh notin m.flags:
|
||||
incl m.flags, includesStringh
|
||||
discard lists.includeStr(m.headerFiles, "<string.h>")
|
||||
|
||||
proc useHeader(m: BModule, sym: PSym) =
|
||||
@@ -129,7 +129,7 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
if i - 1 >= start:
|
||||
add(result, substr(frmt, start, i - 1))
|
||||
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
||||
ropecg(m, fmt, args)
|
||||
|
||||
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
@@ -215,7 +215,7 @@ proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
|
||||
template compileToCpp(m: BModule): expr =
|
||||
template compileToCpp(m: BModule): untyped =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||
|
||||
include "ccgtypes.nim"
|
||||
@@ -301,7 +301,8 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
|
||||
let typ = skipTypes(loc.t, abstractRange)
|
||||
if not isComplexValueType(typ):
|
||||
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
|
||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
|
||||
getTypeDesc(p.module, typ))
|
||||
else:
|
||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||
# don't use memset for temporary values for performance if we can
|
||||
@@ -327,10 +328,12 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
inc(p.labels)
|
||||
result.r = "LOC" & rope(p.labels)
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||
addf(p.blocks[0].sections[cpsLocals],
|
||||
"$1 $2;$n", [getTypeDesc(p.module, t), result.r])
|
||||
result.k = locTemp
|
||||
#result.a = - 1
|
||||
result.t = getUniqueType(t)
|
||||
result.t = t
|
||||
#result.t = getUniqueType(t)
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
constructLoc(p, result, not needsInit)
|
||||
@@ -498,7 +501,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
assert(lib != nil)
|
||||
if not lib.generated:
|
||||
lib.generated = true
|
||||
var tmp = getGlobalTempName()
|
||||
var tmp = getTempName(m)
|
||||
assert(lib.name == nil)
|
||||
lib.name = tmp # BUGFIX: cgsym has awful side-effects
|
||||
addf(m.s[cfsVars], "static void* $1;$n", [tmp])
|
||||
@@ -666,7 +669,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
fillResult(res)
|
||||
assignParam(p, res)
|
||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||
incl(res.loc.flags, lfIndirect)
|
||||
#incl(res.loc.flags, lfIndirect)
|
||||
res.loc.s = OnUnknown
|
||||
|
||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||
@@ -1009,11 +1012,11 @@ proc genInitCode(m: BModule) =
|
||||
add(prc, m.postInitProc.s(cpsLocals))
|
||||
add(prc, genSectionEnd(cpsLocals))
|
||||
|
||||
if optStackTrace in m.initProc.options and not m.frameDeclared:
|
||||
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
# declare it nevertheless:
|
||||
m.frameDeclared = true
|
||||
if not m.preventStackTrace:
|
||||
incl m.flags, frameDeclared
|
||||
if preventStackTrace notin m.flags:
|
||||
var procname = makeCString(m.module.name.s)
|
||||
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
else:
|
||||
@@ -1030,7 +1033,7 @@ proc genInitCode(m: BModule) =
|
||||
add(prc, m.initProc.s(cpsStmts))
|
||||
add(prc, m.postInitProc.s(cpsStmts))
|
||||
add(prc, genSectionEnd(cpsStmts))
|
||||
if optStackTrace in m.initProc.options and not m.preventStackTrace:
|
||||
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
||||
add(prc, deinitFrame(m.initProc))
|
||||
add(prc, deinitGCFrame(m.initProc))
|
||||
addf(prc, "}$N$N", [])
|
||||
@@ -1059,9 +1062,8 @@ proc genModule(m: BModule, cfile: string): Rope =
|
||||
result = getFileHeader(cfile)
|
||||
result.add(genMergeInfo(m))
|
||||
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
generateHeaders(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
add(result, genSectionStart(i))
|
||||
add(result, m.s[i])
|
||||
@@ -1083,6 +1085,7 @@ proc initProcOptions(m: BModule): TOptions =
|
||||
|
||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
result.tmpBase = rope("T" & $hashOwner(module) & "_")
|
||||
initLinkedList(result.headerFiles)
|
||||
result.declaredThings = initIntSet()
|
||||
result.declaredProtos = initIntSet()
|
||||
@@ -1099,12 +1102,12 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
initNodeTable(result.dataCache)
|
||||
result.typeStack = @[]
|
||||
result.forwardedProcs = @[]
|
||||
result.typeNodesName = getTempName()
|
||||
result.nimTypesName = getTempName()
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
result.preventStackTrace = true
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
excl(result.postInitProc.options, optStackTrace)
|
||||
|
||||
@@ -1125,11 +1128,13 @@ proc resetModule*(m: BModule) =
|
||||
initNodeTable(m.dataCache)
|
||||
m.typeStack = @[]
|
||||
m.forwardedProcs = @[]
|
||||
m.typeNodesName = getTempName()
|
||||
m.nimTypesName = getTempName()
|
||||
m.preventStackTrace = sfSystemModule in m.module.flags
|
||||
m.typeNodesName = getTempName(m)
|
||||
m.nimTypesName = getTempName(m)
|
||||
if sfSystemModule in m.module.flags:
|
||||
incl m.flags, preventStackTrace
|
||||
else:
|
||||
excl m.flags, preventStackTrace
|
||||
nullify m.s
|
||||
m.usesThreadVars = false
|
||||
m.typeNodes = 0
|
||||
m.nimTypes = 0
|
||||
nullify m.extensionLoaders
|
||||
@@ -1174,7 +1179,7 @@ proc myOpen(module: PSym): PPassContext =
|
||||
let f = if headerFile.len > 0: headerFile else: gProjectFull
|
||||
generatedHeader = rawNewModule(module,
|
||||
changeFileExt(completeCFilePath(f), hExt))
|
||||
generatedHeader.isHeaderFile = true
|
||||
incl generatedHeader.flags, isHeaderFile
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
var result = getCopyright(m.filename)
|
||||
@@ -1306,7 +1311,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||
registerModuleToMain(m.module)
|
||||
|
||||
if sfMainModule in m.module.flags:
|
||||
m.objHasKidsValid = true
|
||||
incl m.flags, objHasKidsValid
|
||||
var disp = generateMethodDispatchers()
|
||||
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
|
||||
genMainProc(m)
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
from msgs import TLineInfo
|
||||
|
||||
type
|
||||
TLabel* = Rope # for the C generator a label is just a rope
|
||||
TLabel* = Rope # for the C generator a label is just a rope
|
||||
TCFileSection* = enum # the sections a generated C file consists of
|
||||
cfsMergeInfo, # section containing merge information
|
||||
cfsHeaders, # section for C include file headers
|
||||
@@ -89,28 +89,32 @@ type
|
||||
# requires 'T x = T()' to become 'T x; x = T()'
|
||||
# (yes, C++ is weird like that)
|
||||
gcFrameId*: Natural # for the GC stack marking
|
||||
gcFrameType*: Rope # the struct {} we put the GC markers into
|
||||
gcFrameType*: Rope # the struct {} we put the GC markers into
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
|
||||
Codegenflag* = enum
|
||||
preventStackTrace, # true if stack traces need to be prevented
|
||||
usesThreadVars, # true if the module uses a thread var
|
||||
frameDeclared, # hack for ROD support so that we don't declare
|
||||
# a frame var twice in an init proc
|
||||
isHeaderFile, # C source file is the header file
|
||||
includesStringh, # C source file already includes ``<string.h>``
|
||||
objHasKidsValid # whether we can rely on tfObjHasKids
|
||||
TCGen = object of TPassContext # represents a C source file
|
||||
s*: TCFileSections # sections of the C file
|
||||
flags*: set[Codegenflag]
|
||||
module*: PSym
|
||||
filename*: string
|
||||
s*: TCFileSections # sections of the C file
|
||||
preventStackTrace*: bool # true if stack traces need to be prevented
|
||||
usesThreadVars*: bool # true if the module uses a thread var
|
||||
frameDeclared*: bool # hack for ROD support so that we don't declare
|
||||
# a frame var twice in an init proc
|
||||
isHeaderFile*: bool # C source file is the header file
|
||||
includesStringh*: bool # C source file already includes ``<string.h>``
|
||||
objHasKidsValid*: bool # whether we can rely on tfObjHasKids
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
tmpBase*: Rope # base for temp identifier generation
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
forwTypeCache*: TIdTable # cache for forward declarations of types
|
||||
declaredThings*: IntSet # things we have declared in this .c file
|
||||
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||
declaredThings*: IntSet # things we have declared in this .c file
|
||||
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||
headerFiles*: TLinkedList # needed headers to include
|
||||
typeInfoMarker*: IntSet # needed for generating type information
|
||||
typeInfoMarker*: IntSet # needed for generating type information
|
||||
initProc*: BProc # code for init procedure
|
||||
postInitProc*: BProc # code to be executed after the init proc
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
|
||||
@@ -63,19 +63,25 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
|
||||
while true:
|
||||
aa = skipTypes(aa, {tyGenericInst})
|
||||
bb = skipTypes(bb, {tyGenericInst})
|
||||
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
|
||||
if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}:
|
||||
aa = aa.lastSon
|
||||
bb = bb.lastSon
|
||||
else:
|
||||
break
|
||||
if sameType(aa, bb):
|
||||
if aa.kind == tyObject and result != Invalid: result = Yes
|
||||
if aa.kind == tyObject and result != Invalid:
|
||||
result = Yes
|
||||
elif aa.kind == tyObject and bb.kind == tyObject:
|
||||
let diff = inheritanceDiff(bb, aa)
|
||||
if diff < 0:
|
||||
if result != Invalid: result = Yes
|
||||
if result != Invalid:
|
||||
result = Yes
|
||||
else:
|
||||
return No
|
||||
elif diff != high(int):
|
||||
result = Invalid
|
||||
else:
|
||||
return No
|
||||
else:
|
||||
return No
|
||||
|
||||
@@ -181,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
var bb = skipTypes(b.typ.sons[col], skipPtrs)
|
||||
var d = inheritanceDiff(aa, bb)
|
||||
if (d != high(int)):
|
||||
if (d != high(int)) and d != 0:
|
||||
return d
|
||||
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
# We do this here before the 'import' statement so 'defined' does not get
|
||||
# confused with 'TGCMode.gcGenerational' etc.
|
||||
template bootSwitch(name, expr, userString: expr): expr =
|
||||
template bootSwitch(name, expr, userString) =
|
||||
# Helper to build boot constants, for debugging you can 'echo' the else part.
|
||||
const name = if expr: " " & userString else: ""
|
||||
|
||||
@@ -158,7 +158,7 @@ var
|
||||
enableNotes: TNoteKinds
|
||||
disableNotes: TNoteKinds
|
||||
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string) =
|
||||
var id = "" # arg = "X]:on|off"
|
||||
var i = 0
|
||||
@@ -181,10 +181,13 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
case whichKeyword(substr(arg, i))
|
||||
of wOn:
|
||||
incl(gNotes, n)
|
||||
incl(gMainPackageNotes, n)
|
||||
incl(enableNotes, n)
|
||||
of wOff:
|
||||
excl(gNotes, n)
|
||||
excl(gMainPackageNotes, n)
|
||||
incl(disableNotes, n)
|
||||
excl(ForeignPackageNotes, n)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processCompile(filename: string) =
|
||||
@@ -213,6 +216,16 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||
of "size": result = contains(gOptions, optOptimizeSize)
|
||||
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
||||
of "verbosity": result = $gVerbosity == arg
|
||||
of "app":
|
||||
case arg.normalize
|
||||
of "gui": result = contains(gGlobalOptions, optGenGuiApp)
|
||||
of "console": result = not contains(gGlobalOptions, optGenGuiApp)
|
||||
of "lib": result = contains(gGlobalOptions, optGenDynLib) and
|
||||
not contains(gGlobalOptions, optGenGuiApp)
|
||||
of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
|
||||
not contains(gGlobalOptions, optGenGuiApp)
|
||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
@@ -253,20 +266,18 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
of "experimental": result = gExperimentalMode
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc processPath(path: string, notRelativeToProj = false,
|
||||
cfginfo = unknownLineInfo()): string =
|
||||
proc processPath(path: string, info: TLineInfo,
|
||||
notRelativeToProj = false): string =
|
||||
let p = if notRelativeToProj or os.isAbsolute(path) or
|
||||
'$' in path or path[0] == '.':
|
||||
path
|
||||
else:
|
||||
options.gProjectPath / path
|
||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
|
||||
"nim", getPrefixDir(),
|
||||
"lib", libpath,
|
||||
"home", removeTrailingDirSep(os.getHomeDir()),
|
||||
"config", cfginfo.toFullPath().splitFile().dir,
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
try:
|
||||
result = pathSubs(p, info.toFullPath().splitFile().dir)
|
||||
except ValueError:
|
||||
localError(info, "invalid path: " & p)
|
||||
result = p
|
||||
|
||||
proc trackDirty(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
@@ -307,19 +318,22 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
case switch.normalize
|
||||
of "path", "p":
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg, cfginfo=info), info)
|
||||
addPath(processPath(arg, info), info)
|
||||
of "nimblepath", "babelpath":
|
||||
# keep the old name for compat
|
||||
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg, notRelativeToProj=true)
|
||||
let path = processPath(arg, info, notRelativeToProj=true)
|
||||
nimblePath(path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
options.gNoNimblePath = true
|
||||
options.lazyPaths.head = nil
|
||||
options.lazyPaths.tail = nil
|
||||
options.lazyPaths.counter = 0
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
let path = processPath(arg, info)
|
||||
lists.excludePath(options.searchPaths, path)
|
||||
lists.excludePath(options.lazyPaths, path)
|
||||
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
|
||||
@@ -328,7 +342,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
lists.excludePath(options.lazyPaths, strippedPath)
|
||||
of "nimcache":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.nimcacheDir = processPath(arg, true)
|
||||
options.nimcacheDir = processPath(arg, info, true)
|
||||
of "out", "o":
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.outFile = arg
|
||||
@@ -339,7 +353,11 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
discard "allow for backwards compatibility, but don't do anything"
|
||||
of "define", "d":
|
||||
expectArg(switch, arg, pass, info)
|
||||
defineSymbol(arg)
|
||||
if {':', '='} in arg:
|
||||
splitSwitch(arg, key, val, pass, info)
|
||||
defineSymbol(key, val)
|
||||
else:
|
||||
defineSymbol(arg)
|
||||
of "undef", "u":
|
||||
expectArg(switch, arg, pass, info)
|
||||
undefSymbol(arg)
|
||||
@@ -407,6 +425,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
|
||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||
of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info)
|
||||
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
|
||||
of "debugger":
|
||||
case arg.normalize
|
||||
@@ -493,13 +512,13 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
|
||||
of "cincludes":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
|
||||
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
|
||||
of "clibdir":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cLibs.add arg.processPath
|
||||
if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info)
|
||||
of "clib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
|
||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
|
||||
of "header":
|
||||
headerFile = arg
|
||||
incl(gGlobalOptions, optGenIndex)
|
||||
@@ -540,6 +559,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
gNotes = NotesVerbosity[gVerbosity]
|
||||
incl(gNotes, enableNotes)
|
||||
excl(gNotes, disableNotes)
|
||||
gMainPackageNotes = gNotes
|
||||
of "parallelbuild":
|
||||
expectArg(switch, arg, pass, info)
|
||||
gNumberOfProcessors = parseInt(arg)
|
||||
@@ -572,7 +592,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
|
||||
of "lib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
libpath = processPath(arg, notRelativeToProj=true)
|
||||
libpath = processPath(arg, info, notRelativeToProj=true)
|
||||
of "putenv":
|
||||
expectArg(switch, arg, pass, info)
|
||||
splitSwitch(arg, key, val, pass, info)
|
||||
|
||||
@@ -19,8 +19,8 @@ var gSymbols: StringTableRef
|
||||
const
|
||||
catNone = "false"
|
||||
|
||||
proc defineSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "true"
|
||||
proc defineSymbol*(symbol: string, value: string = "true") =
|
||||
gSymbols[symbol] = value
|
||||
|
||||
proc undefSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = catNone
|
||||
@@ -62,6 +62,11 @@ proc isDefined*(symbol: string): bool =
|
||||
|
||||
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
||||
|
||||
proc lookupSymbol*(symbol: string): string =
|
||||
result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||
|
||||
proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
|
||||
|
||||
iterator definedSymbolNames*: string =
|
||||
for key, val in pairs(gSymbols):
|
||||
if val != catNone: yield key
|
||||
@@ -93,3 +98,4 @@ proc initDefines*() =
|
||||
defineSymbol("nimtypedescfixed")
|
||||
defineSymbol("nimKnowsNimvm")
|
||||
defineSymbol("nimArrIdx")
|
||||
defineSymbol("nimImmediateDeprecated")
|
||||
|
||||
81
compiler/debuginfo.nim
Normal file
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
|
||||
ast, strutils, strtabs, options, msgs, os, ropes, idents,
|
||||
wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
|
||||
importer, sempass2, json, xmltree, cgi, typesrenderer
|
||||
importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, Rope]
|
||||
@@ -25,9 +25,32 @@ type
|
||||
indexValFilename: string
|
||||
analytics: string # Google Analytics javascript, "" if doesn't exist
|
||||
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
|
||||
jArray: JsonNode
|
||||
types: TStrTable
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
proc whichType(d: PDoc; n: PNode): PSym =
|
||||
if n.kind == nkSym:
|
||||
if d.types.strTableContains(n.sym):
|
||||
result = n.sym
|
||||
else:
|
||||
for i in 0..<safeLen(n):
|
||||
let x = whichType(d, n[i])
|
||||
if x != nil: return x
|
||||
|
||||
proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
let params = p.ast.sons[paramsPos]
|
||||
# first check the first parameter, then the return type,
|
||||
# then the other parameter:
|
||||
template check(i) =
|
||||
result = whichType(d, params[i])
|
||||
if result != nil: return result
|
||||
|
||||
if params.len > 1: check(1)
|
||||
if params.len > 0: check(0)
|
||||
for i in 2..<params.len: check(i)
|
||||
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.MsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
@@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
|
||||
result.seenSymbols = newStringTable(modeCaseInsensitive)
|
||||
result.id = 100
|
||||
result.jArray = newJArray()
|
||||
initStrTable result.types
|
||||
|
||||
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if gCmd != cmdRst2tex: addf(dest, xml, args)
|
||||
@@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
result = esc(d.target, "`")
|
||||
for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
|
||||
result.add esc(d.target, "`")
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getName(d, n[0], splitAfter)
|
||||
else:
|
||||
internalError(n.info, "getName()")
|
||||
result = ""
|
||||
|
||||
proc getNameIdent(n: PNode): PIdent =
|
||||
case n.kind
|
||||
of nkPostfix: result = getNameIdent(n.sons[1])
|
||||
of nkPragmaExpr: result = getNameIdent(n.sons[0])
|
||||
of nkSym: result = n.sym.name
|
||||
of nkIdent: result = n.ident
|
||||
of nkAccQuoted:
|
||||
var r = ""
|
||||
for i in 0.. <n.len: r.add(getNameIdent(n[i]).s)
|
||||
result = getIdent(r)
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getNameIdent(n[0])
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc getRstName(n: PNode): PRstNode =
|
||||
case n.kind
|
||||
of nkPostfix: result = getRstName(n.sons[1])
|
||||
@@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
|
||||
of nkAccQuoted:
|
||||
result = getRstName(n.sons[0])
|
||||
for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getRstName(n[0])
|
||||
else:
|
||||
internalError(n.info, "getRstName()")
|
||||
result = nil
|
||||
@@ -311,7 +355,7 @@ proc docstringSummary(rstText: string): string =
|
||||
## Also, we hope to not break the rst, but maybe we do. If there is any
|
||||
## trimming done, an ellipsis unicode char is added.
|
||||
const maxDocstringChars = 100
|
||||
assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
|
||||
assert(rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
|
||||
result = rstText.substr(2).strip
|
||||
var pos = result.find('\L')
|
||||
if pos > 0:
|
||||
@@ -380,13 +424,27 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
add(result, literal)
|
||||
of tkCurlyDotLe:
|
||||
dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
|
||||
"\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkCurlyDotRi:
|
||||
dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
|
||||
"\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||
tkBracketDotLe, tkBracketDotRi, tkParDotLe,
|
||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
|
||||
if k in routineKinds and nameNode.kind == nkSym:
|
||||
let att = attachToType(d, nameNode.sym)
|
||||
if att != nil:
|
||||
dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "",
|
||||
[rope esc(d.target, att.name.s)])
|
||||
inc(d.id)
|
||||
let
|
||||
plainNameRope = rope(xmltree.escape(plainName.strip))
|
||||
@@ -402,12 +460,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
var seeSrcRope: Rope = nil
|
||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
|
||||
# XXX toFilename doesn't really work. We need to ensure that this keeps
|
||||
# returning a relative path.
|
||||
let path = n.info.toFilename.extractFilename.rope
|
||||
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
|
||||
["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
|
||||
["path", "line"], [path, rope($n.info.line)])
|
||||
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
|
||||
["path", "line", "url"], [n.info.toFilename.rope,
|
||||
["path", "line", "url"], [path,
|
||||
rope($n.info.line), urlRope])])
|
||||
|
||||
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
@@ -431,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
|
||||
setIndexTerm(d[], symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
if k == skType and nameNode.kind == nkSym:
|
||||
d.types.strTableAdd nameNode.sym
|
||||
|
||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
if not isVisible(nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
@@ -441,8 +500,8 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
|
||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||
|
||||
result = %{ "name": %name, "type": %($k) }
|
||||
|
||||
result = %{ "name": %name, "type": %($k), "line": %n.info.line,
|
||||
"col": %n.info.col}
|
||||
if comm != nil and comm != "":
|
||||
result["description"] = %comm
|
||||
if r.buf != nil:
|
||||
@@ -492,46 +551,45 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
else: discard
|
||||
|
||||
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
|
||||
proc add(d: PDoc; j: JsonNode) =
|
||||
if j != nil: d.jArray.add j
|
||||
|
||||
proc generateJson*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
let stripped = n.comment.substr(2).strip
|
||||
result = %{ "comment": %stripped }
|
||||
d.add %{ "comment": %stripped, "line": %n.info.line,
|
||||
"col": %n.info.col }
|
||||
of nkProcDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skProc)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skProc)
|
||||
of nkMethodDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMethod)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skMethod)
|
||||
of nkIteratorDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skIterator)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skIterator)
|
||||
of nkMacroDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skMacro)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skMacro)
|
||||
of nkTemplateDef:
|
||||
result = genJSONItem(d, n, n.sons[namePos], skTemplate)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
|
||||
of nkConverterDef:
|
||||
when useEffectSystem: documentRaises(n)
|
||||
result = genJSONItem(d, n, n.sons[namePos], skConverter)
|
||||
d.add genJsonItem(d, n, n.sons[namePos], skConverter)
|
||||
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkCommentStmt:
|
||||
# order is always 'type var let const':
|
||||
result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
|
||||
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||
of nkStmtList:
|
||||
result = if jArray != nil: jArray else: newJArray()
|
||||
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var r = generateJson(d, n.sons[i], result)
|
||||
if r != nil:
|
||||
result.add(r)
|
||||
|
||||
generateJson(d, n.sons[i])
|
||||
of nkWhenStmt:
|
||||
# generate documentation for the first branch only:
|
||||
if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
|
||||
discard generateJson(d, lastSon(n.sons[0]), jArray)
|
||||
if not checkForFalse(n.sons[0].sons[0]):
|
||||
generateJson(d, lastSon(n.sons[0]))
|
||||
else: discard
|
||||
|
||||
proc genSection(d: PDoc, kind: TSymKind) =
|
||||
@@ -593,12 +651,36 @@ proc generateIndex*(d: PDoc) =
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
splitFile(d.filename).name & IndexExt)
|
||||
|
||||
proc getOutFile2(filename, ext, dir: string): string =
|
||||
if gWholeProject:
|
||||
let d = if options.outFile != "": options.outFile else: dir
|
||||
createDir(d)
|
||||
result = d / changeFileExt(filename, ext)
|
||||
else:
|
||||
result = getOutFile(filename, ext)
|
||||
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
var content = genOutFile(d)
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
writeRope(content, getOutFile(filename, outExt), useWarning)
|
||||
writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
|
||||
|
||||
proc writeOutputJson*(d: PDoc, filename, outExt: string,
|
||||
useWarning = false) =
|
||||
let content = %*{"orig": d.filename,
|
||||
"nimble": getPackageName(d.filename),
|
||||
"entries": d.jArray}
|
||||
if optStdout in gGlobalOptions:
|
||||
write(stdout, $content)
|
||||
else:
|
||||
var f: File
|
||||
if open(f, getOutFile2(splitFile(filename).name,
|
||||
outExt, "jsondocs"), fmWrite):
|
||||
write(f, $content)
|
||||
close(f)
|
||||
else:
|
||||
discard "fixme: error report"
|
||||
|
||||
proc commandDoc*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
@@ -629,18 +711,19 @@ proc commandRst2TeX*() =
|
||||
splitter = "\\-"
|
||||
commandRstAux(gProjectFull, TexExt)
|
||||
|
||||
proc commandJSON*() =
|
||||
proc commandJson*() =
|
||||
var ast = parseFile(gProjectMainIdx)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
d.hasToc = true
|
||||
var json = generateJson(d, ast)
|
||||
var content = rope(pretty(json))
|
||||
generateJson(d, ast)
|
||||
let json = d.jArray
|
||||
let content = rope(pretty(json))
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
echo getOutFile(gProjectFull, JsonExt)
|
||||
#echo getOutFile(gProjectFull, JsonExt)
|
||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||
|
||||
proc commandBuildIndex*() =
|
||||
|
||||
@@ -19,21 +19,36 @@ type
|
||||
module: PSym
|
||||
PGen = ref TGen
|
||||
|
||||
proc close(p: PPassContext, n: PNode): PNode =
|
||||
template closeImpl(body: untyped) {.dirty.} =
|
||||
var g = PGen(p)
|
||||
let useWarning = sfMainModule notin g.module.flags
|
||||
if gWholeProject or sfMainModule in g.module.flags:
|
||||
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
|
||||
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
|
||||
if (g.module.owner.id == gMainPackageId and gWholeProject) or
|
||||
sfMainModule in g.module.flags:
|
||||
body
|
||||
try:
|
||||
generateIndex(g.doc)
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc close(p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
|
||||
|
||||
proc closeJson(p: PPassContext, n: PNode): PNode =
|
||||
closeImpl:
|
||||
writeOutputJson(g.doc, g.module.filename, ".json", useWarning)
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
generateDoc(g.doc, n)
|
||||
|
||||
proc processNodeJson(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
generateJson(g.doc, n)
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var g: PGen
|
||||
new(g)
|
||||
@@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext =
|
||||
result = g
|
||||
|
||||
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
|
||||
const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson,
|
||||
close = closeJson)
|
||||
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
discard
|
||||
|
||||
@@ -59,7 +59,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
evalTemplateAux(templ.sons[i], actual, c, res)
|
||||
result.add res
|
||||
|
||||
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
||||
# if the template has zero arguments, it can be called without ``()``
|
||||
# `n` is then a nkSym or something similar
|
||||
var totalParams = case n.kind
|
||||
@@ -75,11 +75,11 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
# their bodies. We could try to fix this, but it may be
|
||||
# wiser to just deprecate immediate templates and macros
|
||||
# now that we have working untyped parameters.
|
||||
genericParams = if sfImmediate in s.flags: 0
|
||||
genericParams = if sfImmediate in s.flags or fromHlo: 0
|
||||
else: s.ast[genericParamsPos].len
|
||||
expectedRegularParams = <s.typ.len
|
||||
givenRegularParams = totalParams - genericParams
|
||||
|
||||
if givenRegularParams < 0: givenRegularParams = 0
|
||||
if totalParams > expectedRegularParams + genericParams:
|
||||
globalError(n.info, errWrongNumberOfArguments)
|
||||
|
||||
@@ -104,14 +104,14 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
var evalTemplateCounter* = 0
|
||||
# to prevent endless recursion in templates instantiation
|
||||
|
||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
globalError(n.info, errTemplateInstantiationTooNested)
|
||||
result = n
|
||||
|
||||
# replace each param by the corresponding node:
|
||||
var args = evalTemplateArgs(n, tmpl)
|
||||
var args = evalTemplateArgs(n, tmpl, fromHlo)
|
||||
var ctx: TemplCtx
|
||||
ctx.owner = tmpl
|
||||
ctx.genSymOwner = genSymOwner
|
||||
|
||||
@@ -16,6 +16,8 @@ import
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
securehash, streams
|
||||
|
||||
from debuginfo import writeDebugInfo
|
||||
|
||||
type
|
||||
TSystemCC* = enum
|
||||
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
|
||||
@@ -59,7 +61,7 @@ type
|
||||
# When adding new compilers, the cmake sources could be a good reference:
|
||||
# http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
|
||||
|
||||
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
|
||||
template compiler(name, settings: untyped): untyped =
|
||||
proc name: TInfoCC {.compileTime.} = settings
|
||||
|
||||
# GNU C and C++ Compiler
|
||||
@@ -736,6 +738,8 @@ proc callCCompiler*(projectfile: string) =
|
||||
if not noAbsolutePaths():
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
if optCDebug in gGlobalOptions:
|
||||
writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")
|
||||
@@ -750,7 +754,7 @@ proc callCCompiler*(projectfile: string) =
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
execExternalProgram(linkCmd,
|
||||
if gVerbosity > 1: hintExecuting else: hintLinking)
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
|
||||
@@ -728,12 +728,12 @@ proc simpleSlice*(a, b: PNode): BiggestInt =
|
||||
result = -1
|
||||
|
||||
|
||||
template isMul(x): expr = x.getMagic in someMul
|
||||
template isDiv(x): expr = x.getMagic in someDiv
|
||||
template isAdd(x): expr = x.getMagic in someAdd
|
||||
template isSub(x): expr = x.getMagic in someSub
|
||||
template isVal(x): expr = x.kind in {nkCharLit..nkUInt64Lit}
|
||||
template isIntVal(x, y): expr = x.intVal == y
|
||||
template isMul(x): untyped = x.getMagic in someMul
|
||||
template isDiv(x): untyped = x.getMagic in someDiv
|
||||
template isAdd(x): untyped = x.getMagic in someAdd
|
||||
template isSub(x): untyped = x.getMagic in someSub
|
||||
template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit}
|
||||
template isIntVal(x, y): untyped = x.intVal == y
|
||||
|
||||
import macros
|
||||
|
||||
@@ -776,8 +776,8 @@ proc isMinusOne(n: PNode): bool =
|
||||
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
|
||||
|
||||
proc ple(m: TModel; a, b: PNode): TImplication =
|
||||
template `<=?`(a,b): expr = ple(m,a,b) == impYes
|
||||
template `>=?`(a,b): expr = ple(m, nkIntLit.newIntNode(b), a) == impYes
|
||||
template `<=?`(a,b): untyped = ple(m,a,b) == impYes
|
||||
template `>=?`(a,b): untyped = ple(m, nkIntLit.newIntNode(b), a) == impYes
|
||||
|
||||
# 0 <= 3
|
||||
if a.isValue and b.isValue:
|
||||
|
||||
@@ -24,7 +24,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
of skMacro:
|
||||
result = semMacroExpr(c, n, orig, s)
|
||||
of skTemplate:
|
||||
result = semTemplateExpr(c, n, s)
|
||||
result = semTemplateExpr(c, n, s, {efFromHlo})
|
||||
else:
|
||||
result = semDirectOp(c, n, {})
|
||||
if optHints in gOptions and hintPattern in gNotes:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import idents, strutils, os, options
|
||||
|
||||
var gFrontEndId, gBackendId*: int
|
||||
var gFrontEndId*: int
|
||||
|
||||
const
|
||||
debugIds* = false
|
||||
@@ -30,10 +30,6 @@ proc getID*(): int {.inline.} =
|
||||
result = gFrontEndId
|
||||
inc(gFrontEndId)
|
||||
|
||||
proc backendId*(): int {.inline.} =
|
||||
result = gBackendId
|
||||
inc(gBackendId)
|
||||
|
||||
proc setId*(id: int) {.inline.} =
|
||||
gFrontEndId = max(gFrontEndId, id + 1)
|
||||
|
||||
@@ -49,7 +45,6 @@ proc toGid(f: string): string =
|
||||
proc saveMaxIds*(project: string) =
|
||||
var f = open(project.toGid, fmWrite)
|
||||
f.writeLine($gFrontEndId)
|
||||
f.writeLine($gBackendId)
|
||||
f.close()
|
||||
|
||||
proc loadMaxIds*(project: string) =
|
||||
@@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) =
|
||||
if f.readLine(line):
|
||||
var backEndId = parseInt(line)
|
||||
gFrontEndId = max(gFrontEndId, frontEndId)
|
||||
gBackendId = max(gBackendId, backEndId)
|
||||
f.close()
|
||||
|
||||
@@ -22,7 +22,11 @@ proc getModuleName*(n: PNode): string =
|
||||
# The proc won't perform any checks that the path is actually valid
|
||||
case n.kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
result = unixToNativePath(n.strVal)
|
||||
try:
|
||||
result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
|
||||
except ValueError:
|
||||
localError(n.info, "invalid path: " & n.strVal)
|
||||
result = n.strVal
|
||||
of nkIdent:
|
||||
result = n.ident.s
|
||||
of nkSym:
|
||||
@@ -172,7 +176,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
|
||||
var m = myImportModule(c, n.sons[i])
|
||||
if m != nil:
|
||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
importAllSymbolsExcept(c, m, emptySet)
|
||||
#importForwarded(c, m.ast, emptySet)
|
||||
|
||||
@@ -182,7 +186,7 @@ proc evalFrom(c: PContext, n: PNode): PNode =
|
||||
var m = myImportModule(c, n.sons[0])
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkNilLit:
|
||||
importSymbol(c, n.sons[i], m)
|
||||
@@ -193,7 +197,7 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||
var m = myImportModule(c, n.sons[0])
|
||||
if m != nil:
|
||||
n.sons[0] = newSymNode(m)
|
||||
addDecl(c, m) # add symbol to symbol table of module
|
||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||
var exceptSet = initIntSet()
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
let ident = lookups.considerQuotedIdent(n.sons[i])
|
||||
|
||||
@@ -8,7 +8,7 @@ Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
|
||||
macosx: i386;amd64;powerpc64
|
||||
solaris: i386;amd64;sparc
|
||||
solaris: i386;amd64;sparc;sparc64
|
||||
freebsd: i386;amd64
|
||||
netbsd: i386;amd64
|
||||
openbsd: i386;amd64
|
||||
@@ -48,8 +48,8 @@ Start: "doc/overview.html"
|
||||
[Other]
|
||||
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
|
||||
Files: "makefile"
|
||||
Files: "*.ini"
|
||||
Files: "koch.nim"
|
||||
Files: "install_nimble.nims"
|
||||
|
||||
Files: "icons/nim.ico"
|
||||
Files: "icons/nim.rc"
|
||||
@@ -60,176 +60,26 @@ Files: "icons/koch.rc"
|
||||
Files: "icons/koch.res"
|
||||
Files: "icons/koch_icon.o"
|
||||
|
||||
Files: "compiler/readme.txt"
|
||||
Files: "compiler/installer.ini"
|
||||
Files: "compiler/*.cfg"
|
||||
Files: "compiler/*.nim"
|
||||
Files: "doc/*.txt"
|
||||
Files: "doc/manual/*.txt"
|
||||
Files: "doc/*.nim"
|
||||
Files: "doc/*.cfg"
|
||||
Files: "compiler/nimfix/*.nim"
|
||||
Files: "compiler/nimfix/*.cfg"
|
||||
Files: "compiler/nimsuggest/*.nim"
|
||||
Files: "compiler/nimsuggest/*.cfg"
|
||||
Files: "compiler/plugins/locals/*.nim"
|
||||
Files: "compiler/plugins/*.nim"
|
||||
Files: "tools/*.nim"
|
||||
Files: "tools/*.cfg"
|
||||
Files: "tools/*.tmpl"
|
||||
Files: "tools/niminst/*.nim"
|
||||
Files: "tools/niminst/*.cfg"
|
||||
Files: "tools/niminst/*.tmpl"
|
||||
Files: "tools/niminst/*.nsh"
|
||||
Files: "compiler"
|
||||
Files: "doc"
|
||||
Files: "tools"
|
||||
Files: "web/website.ini"
|
||||
Files: "web/ticker.html"
|
||||
Files: "web/*.nim"
|
||||
Files: "web/*.txt"
|
||||
Files: "web/*.rst"
|
||||
Files: "web/*.csv"
|
||||
Files: "web/news/*.rst"
|
||||
Files: "bin/nimblepkg/*.nim"
|
||||
Files: "bin/nimblepkg/*.cfg"
|
||||
|
||||
[Lib]
|
||||
Files: "lib/nimbase.h"
|
||||
Files: "lib/*.nim"
|
||||
Files: "lib/*.cfg"
|
||||
Files: "lib/*.nimble"
|
||||
|
||||
Files: "lib/system/*.nim"
|
||||
Files: "lib/core/*.nim"
|
||||
Files: "lib/pure/*.nim"
|
||||
Files: "lib/pure/*.cfg"
|
||||
Files: "lib/pure/collections/*.nim"
|
||||
Files: "lib/pure/concurrency/*.nim"
|
||||
Files: "lib/pure/unidecode/*.nim"
|
||||
Files: "lib/pure/concurrency/*.cfg"
|
||||
Files: "lib/impure/*.nim"
|
||||
Files: "lib/impure/nre/private/*.nim"
|
||||
Files: "lib/wrappers/*.nim"
|
||||
Files: "lib/arch/*.nim"
|
||||
|
||||
Files: "lib/wrappers/readline/*.nim"
|
||||
Files: "lib/wrappers/linenoise/*.nim"
|
||||
Files: "lib/wrappers/linenoise/*.c"
|
||||
Files: "lib/wrappers/linenoise/*.h"
|
||||
|
||||
Files: "lib/windows/*.nim"
|
||||
Files: "lib/posix/*.nim"
|
||||
Files: "lib/js/*.nim"
|
||||
Files: "lib/packages/docutils/*.nim"
|
||||
|
||||
Files: "lib/deprecated/core/*.nim"
|
||||
Files: "lib/deprecated/pure/*.nim"
|
||||
Files: "lib/deprecated/pure/*.cfg"
|
||||
Files: "lib"
|
||||
|
||||
[Other]
|
||||
Files: "examples/*.nim"
|
||||
Files: "examples/c++iface/*.nim"
|
||||
Files: "examples/objciface/*.nim"
|
||||
Files: "examples/cross_calculator/"
|
||||
Files: "examples"
|
||||
#Files: "dist/nimble"
|
||||
|
||||
Files: "examples/*.html"
|
||||
Files: "examples/*.txt"
|
||||
Files: "examples/*.cfg"
|
||||
Files: "examples/*.tmpl"
|
||||
|
||||
Files: "tests/actiontable/*.nim"
|
||||
Files: "tests/alias/*.nim"
|
||||
Files: "tests/ambsym/*.nim"
|
||||
Files: "tests/array/*.nim"
|
||||
Files: "tests/assign/*.nim"
|
||||
Files: "tests/astoverload/*.nim"
|
||||
Files: "tests/async/*.nim"
|
||||
Files: "tests/benchmarks/*.nim"
|
||||
Files: "tests/bind/*.nim"
|
||||
Files: "tests/borrow/*.nim"
|
||||
Files: "tests/casestmt/*.nim"
|
||||
Files: "tests/ccgbugs/*.nim"
|
||||
Files: "tests/clearmsg/*.nim"
|
||||
Files: "tests/closure/*.nim"
|
||||
Files: "tests/cnstseq/*.nim"
|
||||
Files: "tests/collections/*.nim"
|
||||
Files: "tests/compiles/*.nim"
|
||||
Files: "tests/concat/*.nim"
|
||||
Files: "tests/concepts/*.nim"
|
||||
Files: "tests/constr/*.nim"
|
||||
Files: "tests/constraints/*.nim"
|
||||
Files: "tests/controlflow/*.nim"
|
||||
Files: "tests/converter/*.nim"
|
||||
Files: "tests/cpp/*.nim"
|
||||
Files: "tests/defaultprocparam/*.nim"
|
||||
Files: "tests/deprecated/*.nim"
|
||||
Files: "tests/destructor/*.nim"
|
||||
Files: "tests/dir with space/*.nim"
|
||||
Files: "tests/discard/*.nim"
|
||||
Files: "tests/distinct/*.nim"
|
||||
Files: "tests/dll/*.nim"
|
||||
Files: "tests/effects/*.nim"
|
||||
Files: "tests/enum/*.nim"
|
||||
Files: "tests/exception/*.nim"
|
||||
Files: "tests/exprs/*.nim"
|
||||
Files: "tests/fields/*.nim"
|
||||
Files: "tests/float/*.nim"
|
||||
Files: "tests/friends/*.nim"
|
||||
Files: "tests/gc/*.nim"
|
||||
Files: "tests/generics/*.nim"
|
||||
Files: "tests/gensym/*.nim"
|
||||
Files: "tests/global/*.nim"
|
||||
Files: "tests/implicit/*.nim"
|
||||
Files: "tests/init/*.nim"
|
||||
Files: "tests/iter/*.nim"
|
||||
Files: "tests/js/*.nim"
|
||||
Files: "tests/js/*.cfg"
|
||||
Files: "tests/let/*.nim"
|
||||
Files: "tests/lexer/*.nim"
|
||||
Files: "tests/lookups/*.nim"
|
||||
Files: "tests/macros/*.nim"
|
||||
Files: "tests/magics/*.nim"
|
||||
Files: "tests/metatype/*.nim"
|
||||
Files: "tests/method/*.nim"
|
||||
Files: "tests/misc/*.nim"
|
||||
Files: "tests/modules/*.nim"
|
||||
Files: "tests/namedparams/*.nim"
|
||||
Files: "tests/notnil/*.nim"
|
||||
Files: "tests/objects/*.nim"
|
||||
Files: "tests/objvariant/*.nim"
|
||||
Files: "tests/openarray/*.nim"
|
||||
Files: "tests/osproc/*.nim"
|
||||
Files: "tests/overflw/*.nim"
|
||||
Files: "tests/overload/*.nim"
|
||||
Files: "tests/parallel/*.nim"
|
||||
Files: "tests/parallel/*.cfg"
|
||||
Files: "tests/parser/*.nim"
|
||||
Files: "tests/pragmas/*.nim"
|
||||
Files: "tests/proc/*.nim"
|
||||
Files: "tests/procvar/*.nim"
|
||||
Files: "tests/range/*.nim"
|
||||
Files: "tests/rodfiles/*.nim"
|
||||
Files: "tests/seq/*.nim"
|
||||
Files: "tests/sets/*.nim"
|
||||
Files: "tests/showoff/*.nim"
|
||||
Files: "tests/specialops/*.nim"
|
||||
Files: "tests/stdlib/*.nim"
|
||||
Files: "tests/system/*.nim"
|
||||
Files: "tests/template/*.nim"
|
||||
Files: "tests/testament/*.nim"
|
||||
Files: "tests/testdata/*.csv"
|
||||
Files: "tests/testdata/*.html"
|
||||
Files: "tests/testdata/*.json"
|
||||
Files: "tests/testdata/*.txt"
|
||||
Files: "tests/testdata/*.xml"
|
||||
Files: "tests/threads/*.nim"
|
||||
Files: "tests/threads/*.cfg"
|
||||
Files: "tests/trmacros/*.nim"
|
||||
Files: "tests/tuples/*.nim"
|
||||
Files: "tests/typerel/*.nim"
|
||||
Files: "tests/types/*.nim"
|
||||
Files: "tests/usingstmt/*.nim"
|
||||
Files: "tests/varres/*.nim"
|
||||
Files: "tests/varstmt/*.nim"
|
||||
Files: "tests/vm/*.nim"
|
||||
Files: "tests/readme.txt"
|
||||
Files: "tests/testament/css/*.css"
|
||||
Files: "tests/testament/*.cfg"
|
||||
Files: "lib/pure/unidecode/unidecode.dat"
|
||||
Files: "tests"
|
||||
|
||||
[Windows]
|
||||
Files: "bin/nim.exe"
|
||||
@@ -249,7 +99,7 @@ BinPath: r"bin;dist\mingw\bin;dist"
|
||||
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
|
||||
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
|
||||
Download: r"Support DLL's|bin|nim_dlls.zip|479|http://nim-lang.org/download/dlls.zip"
|
||||
Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe"
|
||||
Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
|
||||
; for now only NSIS supports optional downloads
|
||||
|
||||
[UnixBin]
|
||||
@@ -279,3 +129,7 @@ buildDepends: "gcc (>= 4:4.3.2)"
|
||||
pkgDepends: "gcc (>= 4:4.3.2)"
|
||||
shortDesc: "The Nim Compiler"
|
||||
licenses: "bin/nim,MIT;lib/*,MIT;"
|
||||
|
||||
[nimble]
|
||||
pkgName: "compiler"
|
||||
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
|
||||
# This is the JavaScript code generator.
|
||||
# Soon also a PHP code generator. ;-)
|
||||
# Also a PHP code generator. ;-)
|
||||
|
||||
discard """
|
||||
The JS code generator contains only 2 tricks:
|
||||
@@ -48,6 +48,7 @@ type
|
||||
etyNull, # null type
|
||||
etyProc, # proc type
|
||||
etyBool, # bool type
|
||||
etySeq, # Nim seq or string type
|
||||
etyInt, # JavaScript's int
|
||||
etyFloat, # JavaScript's float
|
||||
etyString, # JavaScript's string
|
||||
@@ -71,7 +72,7 @@ type
|
||||
isLoop: bool # whether it's a 'block' or 'while'
|
||||
|
||||
TGlobals = object
|
||||
typeInfo, code: Rope
|
||||
typeInfo, constants, code: Rope
|
||||
forwarded: seq[PSym]
|
||||
generatedSyms: IntSet
|
||||
typeInfoGenerated: IntSet
|
||||
@@ -94,7 +95,7 @@ type
|
||||
up: PProc # up the call chain; required for closure support
|
||||
declaredGlobals: IntSet
|
||||
|
||||
template `|`(a, b: expr): expr {.immediate, dirty.} =
|
||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
||||
(if p.target == targetJS: a else: b)
|
||||
|
||||
proc newGlobals(): PGlobals =
|
||||
@@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||
of tyBool: result = etyBool
|
||||
of tyFloat..tyFloat128: result = etyFloat
|
||||
of tySet: result = etyObject # map a set to a table
|
||||
of tyString, tySequence: result = etyInt # little hack to get right semantics
|
||||
of tyString, tySequence: result = etySeq
|
||||
of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
|
||||
tyVarargs:
|
||||
result = etyObject
|
||||
of tyNil: result = etyNull
|
||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
|
||||
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
||||
tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
|
||||
result = etyNone
|
||||
of tyStatic:
|
||||
if t.n != nil: result = mapType(lastSon t)
|
||||
else: result = etyNone
|
||||
of tyProc: result = etyProc
|
||||
of tyCString: result = etyString
|
||||
|
||||
@@ -237,7 +241,7 @@ proc useMagic(p: PProc, name: string) =
|
||||
internalAssert s.kind in {skProc, skMethod, skConverter}
|
||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
let code = genProc(p, s)
|
||||
add(p.g.code, code)
|
||||
add(p.g.constants, code)
|
||||
else:
|
||||
# we used to exclude the system module from this check, but for DLL
|
||||
# generation support this sloppyness leads to hard to detect bugs, so
|
||||
@@ -359,8 +363,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
|
||||
["", "", "($1 != $2)", "($1 != $2)"], # Xor
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqCString
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqProc
|
||||
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
|
||||
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
|
||||
@@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
||||
return
|
||||
|
||||
let xtyp = mapType(p, x.typ)
|
||||
var xtyp = mapType(p, x.typ)
|
||||
|
||||
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
||||
gen(p, x.sons[0], a)
|
||||
@@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
|
||||
gen(p, y, b)
|
||||
|
||||
# we don't care if it's an etyBaseIndex (global) of a string, it's
|
||||
# still a string that needs to be copied properly:
|
||||
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
|
||||
xtyp = etySeq
|
||||
case xtyp
|
||||
of etySeq:
|
||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
@@ -981,7 +996,7 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = "nimAt($1, $2)" % [r.address, r.res]
|
||||
elif ty.kind in {tyString, tyCString}:
|
||||
# XXX this needs to be more like substr($1,$2)
|
||||
r.res = "ord($1[$2])" % [r.address, r.res]
|
||||
r.res = "ord(@$1[$2])" % [r.address, r.res]
|
||||
else:
|
||||
r.res = "$1[$2]" % [r.address, r.res]
|
||||
else:
|
||||
@@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
||||
of nkObjDownConv:
|
||||
gen(p, n.sons[0], r)
|
||||
of nkHiddenDeref:
|
||||
gen(p, n.sons[0].sons[0], r)
|
||||
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
||||
|
||||
proc thisParam(p: PProc; typ: PType): PType =
|
||||
@@ -1215,11 +1232,13 @@ proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
||||
genArgNoParam(p, it, r)
|
||||
else:
|
||||
genArg(p, it, paramType.sym, r)
|
||||
inc generated
|
||||
|
||||
proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
|
||||
r: var TCompRes) =
|
||||
var i = 0
|
||||
var j = 1
|
||||
r.kind = resExpr
|
||||
while i < pat.len:
|
||||
case pat[i]
|
||||
of '@':
|
||||
@@ -1233,31 +1252,43 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
|
||||
genOtherArg(p, n, j, typ, generated, r)
|
||||
inc j
|
||||
inc i
|
||||
of '\31':
|
||||
# unit separator
|
||||
add(r.res, "#")
|
||||
inc i
|
||||
of '\29':
|
||||
# group separator
|
||||
add(r.res, "@")
|
||||
inc i
|
||||
else:
|
||||
let start = i
|
||||
while i < pat.len:
|
||||
if pat[i] notin {'@', '#'}: inc(i)
|
||||
if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
|
||||
else: break
|
||||
if i - 1 >= start:
|
||||
add(r.res, substr(pat, start, i - 1))
|
||||
|
||||
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# don't call '$' here for efficiency:
|
||||
let pat = n.sons[0].sym.loc.r.data
|
||||
internalAssert pat != nil
|
||||
if pat.contains({'#', '(', '@'}):
|
||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
genPatternCall(p, n, pat, typ, r)
|
||||
return
|
||||
gen(p, n.sons[1], r)
|
||||
if r.typ == etyBaseIndex:
|
||||
if r.address == nil:
|
||||
globalError(n.info, "cannot invoke with infix syntax")
|
||||
r.res = "$1[$2]" % [r.address, r.res]
|
||||
r.address = nil
|
||||
r.typ = etyNone
|
||||
add(r.res, "." | "->")
|
||||
let f = n[0].sym
|
||||
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
|
||||
if sfInfixCall in f.flags:
|
||||
let pat = n.sons[0].sym.loc.r.data
|
||||
internalAssert pat != nil
|
||||
if pat.contains({'#', '(', '@'}):
|
||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
genPatternCall(p, n, pat, typ, r)
|
||||
return
|
||||
if n.len != 1:
|
||||
gen(p, n.sons[1], r)
|
||||
if r.typ == etyBaseIndex:
|
||||
if r.address == nil:
|
||||
globalError(n.info, "cannot invoke with infix syntax")
|
||||
r.res = "$1[$2]" % [r.address, r.res]
|
||||
r.address = nil
|
||||
r.typ = etyNone
|
||||
add(r.res, "." | "->")
|
||||
var op: TCompRes
|
||||
if p.target == targetPHP:
|
||||
op.kind = resCallee
|
||||
@@ -1266,7 +1297,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
genArgs(p, n, r, 2)
|
||||
|
||||
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if thisParam(p, n.sons[0].typ) != nil:
|
||||
if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil:
|
||||
genInfixCall(p, n, r)
|
||||
return
|
||||
if p.target == targetPHP:
|
||||
@@ -1400,6 +1431,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
result = putToSeq("null", indirect)
|
||||
of tySequence, tyString, tyCString, tyPointer, tyProc:
|
||||
result = putToSeq("null", indirect)
|
||||
of tyStatic:
|
||||
if t.n != nil:
|
||||
result = createVar(p, lastSon t, indirect)
|
||||
else:
|
||||
internalError("createVar: " & $t.kind)
|
||||
result = nil
|
||||
else:
|
||||
internalError("createVar: " & $t.kind)
|
||||
result = nil
|
||||
@@ -1409,13 +1446,16 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
a: TCompRes
|
||||
s: Rope
|
||||
if n.kind == nkEmpty:
|
||||
let mname = mangleName(v, p.target)
|
||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||
[mangleName(v, p.target), createVar(p, v.typ, isIndirect(v))])
|
||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
|
||||
addf(p.body, "var $1_Idx = 0;$n", [ mname ])
|
||||
else:
|
||||
discard mangleName(v, p.target)
|
||||
gen(p, n, a)
|
||||
case mapType(p, v.typ)
|
||||
of etyObject:
|
||||
of etyObject, etySeq:
|
||||
if needsNoCopy(p, n):
|
||||
s = a.res
|
||||
else:
|
||||
@@ -1458,7 +1498,7 @@ proc genConstant(p: PProc, c: PSym) =
|
||||
p.body = nil
|
||||
#genLineDir(p, c.ast)
|
||||
genVarInit(p, c, c.ast)
|
||||
add(p.g.code, p.body)
|
||||
add(p.g.constants, p.body)
|
||||
p.body = oldBody
|
||||
|
||||
proc genNew(p: PProc, n: PNode) =
|
||||
@@ -1554,8 +1594,16 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of tyEnum, tyOrdinal:
|
||||
gen(p, n.sons[1], r)
|
||||
useMagic(p, "cstrToNimstr")
|
||||
var offset = ""
|
||||
if t.kind == tyEnum:
|
||||
let firstFieldOffset = t.n.sons[0].sym.position
|
||||
if firstFieldOffset < 0:
|
||||
offset = "+" & $(-firstFieldOffset)
|
||||
elif firstFieldOffset > 0:
|
||||
offset = "-" & $firstFieldOffset
|
||||
|
||||
r.kind = resExpr
|
||||
r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
|
||||
r.res = "cstrToNimstr($1.node.sons[$2$3].name)" % [genTypeInfo(p, t), r.res, rope(offset)]
|
||||
else:
|
||||
# XXX:
|
||||
internalError(n.info, "genRepr: Not implemented")
|
||||
@@ -1645,8 +1693,11 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
|
||||
of mOrd: genOrd(p, n, r)
|
||||
of mLengthStr:
|
||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
|
||||
"strlen($1)")
|
||||
if p.target == targetJS and n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
|
||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
||||
else:
|
||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
|
||||
"strlen($1)")
|
||||
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)")
|
||||
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)" |
|
||||
@@ -1672,8 +1723,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
||||
of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "")
|
||||
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "")
|
||||
of mSetLengthStr:
|
||||
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
|
||||
of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2" | "$1 = array_slice($1, 0, $2)")
|
||||
of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
|
||||
of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
|
||||
of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
|
||||
@@ -1683,8 +1735,31 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
|
||||
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
|
||||
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]")
|
||||
of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)" | "isset($1[$2])")
|
||||
of mInSet:
|
||||
if p.target == targetJS:
|
||||
binaryExpr(p, n, r, "", "($1[$2] != undefined)")
|
||||
else:
|
||||
let s = n.sons[1]
|
||||
if s.kind == nkCurly:
|
||||
var a, b, x: TCompRes
|
||||
gen(p, n.sons[2], x)
|
||||
r.res = rope("(")
|
||||
r.kind = resExpr
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if i > 0: add(r.res, " || ")
|
||||
var it = s.sons[i]
|
||||
if it.kind == nkRange:
|
||||
gen(p, it.sons[0], a)
|
||||
gen(p, it.sons[1], b)
|
||||
addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,])
|
||||
else:
|
||||
gen(p, it, a)
|
||||
addf(r.res, "($1 == $2)", [x.res, a.res])
|
||||
add(r.res, ")")
|
||||
else:
|
||||
binaryExpr(p, n, r, "", "isset($1[$2])")
|
||||
of mNewSeq: genNewSeq(p, n)
|
||||
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
|
||||
of mOf: genOf(p, n, r)
|
||||
of mReset: genReset(p, n)
|
||||
of mEcho: genEcho(p, n, r)
|
||||
@@ -1877,9 +1952,13 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
let header = generateHeader(p, prc.typ)
|
||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast.sons[resultPos].sym
|
||||
let mname = mangleName(resultSym, p.target)
|
||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
||||
mangleName(resultSym, p.target),
|
||||
mname,
|
||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
resultAsgn.add "var $#_Idx = 0;$n" % [
|
||||
mname ];
|
||||
gen(p, prc.ast.sons[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
@@ -1983,7 +2062,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
||||
genMagic(p, n, r)
|
||||
elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
|
||||
n.len >= 2:
|
||||
n.len >= 1:
|
||||
genInfixCall(p, n, r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
@@ -2131,7 +2210,7 @@ proc wholeCode*(m: BModule): Rope =
|
||||
var p = newProc(globals, m, nil, m.module.options)
|
||||
attachProc(p, prc)
|
||||
|
||||
result = globals.typeInfo & globals.code
|
||||
result = globals.typeInfo & globals.constants & globals.code
|
||||
|
||||
proc getClassName(t: PType): Rope =
|
||||
var s = t.sym
|
||||
|
||||
@@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||
of tyEnum: genEnumInfo(p, t, result)
|
||||
of tyObject: genObjectInfo(p, t, result)
|
||||
of tyTuple: genTupleInfo(p, t, result)
|
||||
of tyStatic:
|
||||
if t.n != nil: result = genTypeInfo(p, lastSon t)
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
|
||||
@@ -716,11 +716,16 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
#localError(n.info, "internal error: closure to closure created")
|
||||
# now we know better, so patch it:
|
||||
n.sons[0] = x.sons[0]
|
||||
n.sons[1] = x.sons[1]
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil and n[namePos].kind == nkSym:
|
||||
let m = newSymNode(n[namePos].sym)
|
||||
m.typ = n.typ
|
||||
result = liftCapturedVars(m, owner, d, c)
|
||||
of nkHiddenStdConv:
|
||||
if n.len == 2:
|
||||
n.sons[1] = liftCapturedVars(n[1], owner, d, c)
|
||||
if n[1].kind == nkClosure: result = n[1]
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if n.kind == nkYieldStmt:
|
||||
|
||||
@@ -138,6 +138,8 @@ proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
|
||||
proc isKeyword*(kind: TTokType): bool =
|
||||
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
|
||||
|
||||
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
|
||||
|
||||
proc isNimIdentifier*(s: string): bool =
|
||||
if s[0] in SymStartChars:
|
||||
var i = 1
|
||||
@@ -589,12 +591,29 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||
of '\\':
|
||||
add(tok.literal, '\\')
|
||||
inc(L.bufpos)
|
||||
of 'x', 'X':
|
||||
of 'x', 'X', 'u', 'U':
|
||||
var tp = L.buf[L.bufpos]
|
||||
inc(L.bufpos)
|
||||
var xi = 0
|
||||
handleHexChar(L, xi)
|
||||
handleHexChar(L, xi)
|
||||
add(tok.literal, chr(xi))
|
||||
if tp in {'u', 'U'}:
|
||||
handleHexChar(L, xi)
|
||||
handleHexChar(L, xi)
|
||||
# inlined toUTF-8 to avoid unicode and strutils dependencies.
|
||||
if xi <=% 127:
|
||||
add(tok.literal, xi.char )
|
||||
elif xi <=% 0x07FF:
|
||||
add(tok.literal, ((xi shr 6) or 0b110_00000).char )
|
||||
add(tok.literal, ((xi and ones(6)) or 0b10_0000_00).char )
|
||||
elif xi <=% 0xFFFF:
|
||||
add(tok.literal, (xi shr 12 or 0b1110_0000).char )
|
||||
add(tok.literal, (xi shr 6 and ones(6) or 0b10_0000_00).char )
|
||||
add(tok.literal, (xi and ones(6) or 0b10_0000_00).char )
|
||||
else: # value is 0xFFFF
|
||||
add(tok.literal, "\xef\xbf\xbf" )
|
||||
else:
|
||||
add(tok.literal, chr(xi))
|
||||
of '0'..'9':
|
||||
if matchTwoChars(L, '0', {'0'..'9'}):
|
||||
lexMessage(L, warnOctalEscape)
|
||||
@@ -716,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
if c == '\226' and
|
||||
buf[pos+1] == '\128' and
|
||||
buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode
|
||||
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
|
||||
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or
|
||||
isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos:
|
||||
lexMessage(L, errInvalidToken, "–")
|
||||
break
|
||||
inc(pos, magicIdentSeparatorRuneByteWidth)
|
||||
@@ -728,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
of '_':
|
||||
if buf[pos+1] notin SymChars:
|
||||
if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
inc(pos)
|
||||
@@ -811,10 +831,6 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int;
|
||||
break
|
||||
dec nesting
|
||||
inc pos
|
||||
of '\t':
|
||||
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
||||
inc(pos)
|
||||
if isDoc: tok.literal.add '\t'
|
||||
of CR, LF:
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
@@ -877,10 +893,10 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
inc(indent)
|
||||
|
||||
when defined(nimfix):
|
||||
template doContinue(): expr =
|
||||
template doContinue(): untyped =
|
||||
buf[pos] == '#' and (col == indent or lastBackslash > 0)
|
||||
else:
|
||||
template doContinue(): expr =
|
||||
template doContinue(): untyped =
|
||||
buf[pos] == '#' and buf[pos+1] == '#'
|
||||
if doContinue():
|
||||
tok.literal.add "\n"
|
||||
@@ -926,9 +942,9 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||
break
|
||||
tok.strongSpaceA = 0
|
||||
when defined(nimfix):
|
||||
template doBreak(): expr = buf[pos] > ' '
|
||||
template doBreak(): untyped = buf[pos] > ' '
|
||||
else:
|
||||
template doBreak(): expr =
|
||||
template doBreak(): untyped =
|
||||
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
|
||||
if doBreak():
|
||||
tok.indent = indent
|
||||
@@ -1041,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||
inc(L.bufpos)
|
||||
of '_':
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] notin SymChars:
|
||||
if L.buf[L.bufpos] notin SymChars+{'_'} and not
|
||||
isMagicIdentSeparatorRune(L.buf, L.bufpos):
|
||||
tok.tokType = tkSymbol
|
||||
tok.ident = getIdent("_")
|
||||
else:
|
||||
@@ -1062,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||
tok.tokType = tkCharLit
|
||||
of '0'..'9':
|
||||
getNumber(L, tok)
|
||||
let c = L.buf[L.bufpos]
|
||||
if c in SymChars+{'_'}:
|
||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
||||
else:
|
||||
if c in OpChars:
|
||||
getOperator(L, tok)
|
||||
|
||||
@@ -99,8 +99,11 @@ proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
|
||||
|
||||
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
|
||||
for scope in walkScopes(c.currentScope):
|
||||
result = strTableGet(scope.symbols, s)
|
||||
if result != nil and result.kind in filter: return
|
||||
var ti: TIdentIter
|
||||
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||
while candidate != nil:
|
||||
if candidate.kind in filter: return candidate
|
||||
candidate = nextIdentIter(ti, scope.symbols)
|
||||
result = nil
|
||||
|
||||
proc errorSym*(c: PContext, n: PNode): PSym =
|
||||
@@ -153,7 +156,8 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
|
||||
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
|
||||
# XXX: implicit type params are currently skTypes
|
||||
# maybe they can be made skGenericParam as well.
|
||||
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
|
||||
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
|
||||
s.typ.kind != tyGenericParam:
|
||||
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
|
||||
s = nextIter(it, scope.symbols)
|
||||
|
||||
@@ -161,6 +165,10 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
|
||||
if gCmd != cmdInteractive:
|
||||
localError(info, errAttemptToRedefine, s)
|
||||
|
||||
proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) =
|
||||
if not c.currentScope.addUniqueSym(sym):
|
||||
wrongRedefinition(info, sym.name.s)
|
||||
|
||||
proc addDecl*(c: PContext, sym: PSym) =
|
||||
if not c.currentScope.addUniqueSym(sym):
|
||||
wrongRedefinition(sym.info, sym.name.s)
|
||||
@@ -212,14 +220,27 @@ when defined(nimfix):
|
||||
of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
|
||||
else: result = x
|
||||
|
||||
template fixSpelling(n: PNode; ident: PIdent; op: expr) =
|
||||
template fixSpelling(n: PNode; ident: PIdent; op: untyped) =
|
||||
let alt = ident.altSpelling
|
||||
result = op(c, alt).skipAlias(n)
|
||||
if result != nil:
|
||||
prettybase.replaceDeprecated(n.info, ident, alt)
|
||||
return result
|
||||
else:
|
||||
template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
|
||||
template fixSpelling(n: PNode; ident: PIdent; op: untyped) = discard
|
||||
|
||||
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
|
||||
var err = "Error: ambiguous identifier: '" & s.name.s & "'"
|
||||
var ti: TIdentIter
|
||||
var candidate = initIdentIter(ti, c.importTable.symbols, s.name)
|
||||
var i = 0
|
||||
while candidate != nil:
|
||||
if i == 0: err.add " --use "
|
||||
else: err.add " or "
|
||||
err.add candidate.owner.name.s & "." & candidate.name.s
|
||||
candidate = nextIdentIter(ti, c.importTable.symbols)
|
||||
inc i
|
||||
localError(info, errGenerated, err)
|
||||
|
||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
# Looks up a symbol. Generates an error in case of nil.
|
||||
@@ -243,32 +264,36 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
internalError(n.info, "lookUp")
|
||||
return
|
||||
if contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, result.name.s)
|
||||
errorUseQualifier(c, n.info, result)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
|
||||
type
|
||||
TLookupFlag* = enum
|
||||
checkAmbiguity, checkUndeclared
|
||||
checkAmbiguity, checkUndeclared, checkModule
|
||||
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var ident = considerQuotedIdent(n)
|
||||
result = searchInScopes(c, ident).skipAlias(n)
|
||||
if checkModule in flags:
|
||||
result = searchInScopes(c, ident).skipAlias(n)
|
||||
else:
|
||||
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
fixSpelling(n, ident, searchInScopes)
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(c, n)
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, ident.s)
|
||||
errorUseQualifier(c, n.info, result)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
||||
localError(n.info, errUseQualifier, n.sym.name.s)
|
||||
errorUseQualifier(c, n.info, n.sym)
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
||||
var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule})
|
||||
if m != nil and m.kind == skModule:
|
||||
var ident: PIdent = nil
|
||||
if n.sons[1].kind == nkIdent:
|
||||
@@ -313,7 +338,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.mode = oimDone
|
||||
of nkDotExpr:
|
||||
o.mode = oimOtherModule
|
||||
o.m = qualifiedLookUp(c, n.sons[0])
|
||||
o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule})
|
||||
if o.m != nil and o.m.kind == skModule:
|
||||
var ident: PIdent = nil
|
||||
if n.sons[1].kind == nkIdent:
|
||||
|
||||
@@ -471,6 +471,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||
let slice = newNodeI(nkCall, n.info, 4)
|
||||
slice.typ = n.typ
|
||||
slice.sons[0] = newSymNode(createMagic("slice", mSlice))
|
||||
slice.sons[0].typ = getSysType(tyInt) # fake type
|
||||
var fieldB = newSym(skField, tmpName, objType.owner, n.info)
|
||||
fieldB.typ = getSysType(tyInt)
|
||||
objType.addField(fieldB)
|
||||
@@ -577,6 +578,8 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||
var fn = n.sons[0]
|
||||
# templates and macros are in fact valid here due to the nature of
|
||||
# the transformation:
|
||||
if fn.kind == nkClosure:
|
||||
localError(n.info, "closure in spawn environment is not allowed")
|
||||
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
|
||||
skMethod, skConverter}):
|
||||
# for indirect calls we pass the function pointer in the scratchObj
|
||||
|
||||
@@ -41,11 +41,15 @@ proc getSysSym*(name: string): PSym =
|
||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||
var ti: TIdentIter
|
||||
let id = getIdent(name)
|
||||
result = initIdentIter(ti, systemModule.tab, id)
|
||||
while result != nil:
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.magic == m: return result
|
||||
result = nextIdentIter(ti, systemModule.tab)
|
||||
var r = initIdentIter(ti, systemModule.tab, id)
|
||||
while r != nil:
|
||||
if r.kind == skStub: loadStub(r)
|
||||
if r.magic == m:
|
||||
# prefer the tyInt variant:
|
||||
if r.typ.sons[0].kind == tyInt: return r
|
||||
result = r
|
||||
r = nextIdentIter(ti, systemModule.tab)
|
||||
if result != nil: return result
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, id, systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
|
||||
@@ -41,14 +41,16 @@ proc commandGenDepend =
|
||||
|
||||
proc commandCheck =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
defineSymbol("nimcheck")
|
||||
semanticPasses() # use an empty backend for semantic checking only
|
||||
rodPass()
|
||||
compileProject()
|
||||
|
||||
proc commandDoc2 =
|
||||
proc commandDoc2(json: bool) =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses()
|
||||
registerPass(docgen2Pass)
|
||||
if json: registerPass(docgen2JsonPass)
|
||||
else: registerPass(docgen2Pass)
|
||||
#registerPass(cleanupPass())
|
||||
compileProject()
|
||||
finishDoc2Pass(gProjectName)
|
||||
@@ -241,7 +243,7 @@ proc mainCommand* =
|
||||
clearPasses()
|
||||
gLastCmdTime = epochTime()
|
||||
appendStr(searchPaths, options.libpath)
|
||||
if gProjectFull.len != 0:
|
||||
when false: # gProjectFull.len != 0:
|
||||
# current path is always looked first for modules
|
||||
prependStr(searchPaths, gProjectPath)
|
||||
setId(100)
|
||||
@@ -280,7 +282,7 @@ proc mainCommand* =
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
defineSymbol("nimdoc")
|
||||
commandDoc2()
|
||||
commandDoc2(false)
|
||||
of "rst2html":
|
||||
gCmd = cmdRst2html
|
||||
loadConfigs(DocConfig)
|
||||
@@ -295,7 +297,13 @@ proc mainCommand* =
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
defineSymbol("nimdoc")
|
||||
commandJSON()
|
||||
commandJson()
|
||||
of "jsondoc2":
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
defineSymbol("nimdoc")
|
||||
commandDoc2(true)
|
||||
of "buildindex":
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
|
||||
@@ -29,12 +29,16 @@ var
|
||||
gMemCacheData*: seq[TModuleInMemory] = @[]
|
||||
## XXX: we should implement recycling of file IDs
|
||||
## if the user keeps renaming modules, the file IDs will keep growing
|
||||
gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
|
||||
packageSyms: TStrTable
|
||||
|
||||
initStrTable(packageSyms)
|
||||
|
||||
proc getModule*(fileIdx: int32): PSym =
|
||||
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||
result = gCompiledModules[fileIdx]
|
||||
|
||||
template hash(x: PSym): expr =
|
||||
template hash(x: PSym): untyped =
|
||||
gMemCacheData[x.position].hash
|
||||
|
||||
proc hashChanged(fileIdx: int32): bool =
|
||||
@@ -45,7 +49,7 @@ proc hashChanged(fileIdx: int32): bool =
|
||||
else: hashNotChanged
|
||||
# echo "TESTING Hash: ", fileIdx.toFilename, " ", result
|
||||
|
||||
case gMemCacheData[fileIdx].hashStatus:
|
||||
case gMemCacheData[fileIdx].hashStatus
|
||||
of hashHasChanged:
|
||||
result = true
|
||||
of hashNotChanged:
|
||||
@@ -90,6 +94,7 @@ proc resetAllModules* =
|
||||
if gCompiledModules[i] != nil:
|
||||
resetModule(i.int32)
|
||||
resetPackageCache()
|
||||
initStrTable(packageSyms)
|
||||
# for m in cgenModules(): echo "CGEN MODULE FOUND"
|
||||
|
||||
proc resetAllModulesHard* =
|
||||
@@ -97,6 +102,7 @@ proc resetAllModulesHard* =
|
||||
gCompiledModules.setLen 0
|
||||
gMemCacheData.setLen 0
|
||||
magicsys.resetSysTypes()
|
||||
initStrTable(packageSyms)
|
||||
# XXX
|
||||
#gOwners = @[]
|
||||
|
||||
@@ -105,12 +111,16 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
||||
resetModule(fileIdx)
|
||||
return Yes
|
||||
|
||||
if gMemCacheData[fileIdx].needsRecompile != Maybe:
|
||||
return gMemCacheData[fileIdx].needsRecompile
|
||||
if gFuzzyGraphChecking:
|
||||
if gMemCacheData[fileIdx].needsRecompile != Maybe:
|
||||
return gMemCacheData[fileIdx].needsRecompile
|
||||
else:
|
||||
# cycle detection: We claim that a cycle does no harm.
|
||||
if gMemCacheData[fileIdx].needsRecompile == Probing:
|
||||
return No
|
||||
|
||||
if optForceFullMake in gGlobalOptions or
|
||||
hashChanged(fileIdx):
|
||||
markDirty
|
||||
if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
|
||||
markDirty()
|
||||
|
||||
if gMemCacheData[fileIdx].deps != nil:
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
@@ -118,7 +128,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
||||
let d = checkDepMem(dep)
|
||||
if d in {Yes, Recompiled}:
|
||||
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
|
||||
markDirty
|
||||
markDirty()
|
||||
|
||||
gMemCacheData[fileIdx].needsRecompile = No
|
||||
return No
|
||||
@@ -135,8 +145,16 @@ proc newModule(fileIdx: int32): PSym =
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
|
||||
result.info)
|
||||
let pack = getIdent(getPackageName(filename))
|
||||
var packSym = packageSyms.strTableGet(pack)
|
||||
if packSym == nil:
|
||||
let pck = getPackageName(filename)
|
||||
let pck2 = if pck.len > 0: pck else: "unknown"
|
||||
packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
|
||||
initStrTable(packSym.tab)
|
||||
packageSyms.strTableAdd(packSym)
|
||||
|
||||
result.owner = packSym
|
||||
result.position = fileIdx
|
||||
|
||||
growCache gMemCacheData, fileIdx
|
||||
@@ -146,6 +164,11 @@ proc newModule(fileIdx: int32): PSym =
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
let existing = strTableGet(packSym.tab, result.name)
|
||||
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
|
||||
localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
|
||||
# strTableIncl() for error corrections:
|
||||
discard strTableIncl(packSym.tab, result)
|
||||
|
||||
proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
|
||||
result = getModule(fileIdx)
|
||||
@@ -156,6 +179,9 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
|
||||
#var rd = handleSymbolFile(result)
|
||||
var rd: PRodReader
|
||||
result.flags = result.flags + flags
|
||||
if sfMainModule in result.flags:
|
||||
gMainPackageId = result.owner.id
|
||||
|
||||
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
|
||||
rd = handleSymbolFile(result)
|
||||
if result.id < 0:
|
||||
@@ -181,8 +207,11 @@ proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
|
||||
# this is called by the semantic checking phase
|
||||
result = compileModule(fileIdx, {})
|
||||
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
|
||||
if sfSystemModule in result.flags:
|
||||
localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
#if sfSystemModule in result.flags:
|
||||
# localError(result.info, errAttemptToRedefine, result.name.s)
|
||||
# restore the notes for outer module:
|
||||
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
|
||||
else: ForeignPackageNotes
|
||||
|
||||
proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
||||
result = syntaxes.parseFile(fileIdx)
|
||||
|
||||
@@ -471,6 +471,8 @@ type
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
# purposes
|
||||
quotedFullName*: Rope # cached quoted full name for codegen
|
||||
# purposes
|
||||
|
||||
lines*: seq[Rope] # the source code of the module
|
||||
# used for better error messages and
|
||||
@@ -505,7 +507,7 @@ const
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintSuccessX, hintPath, hintConf,
|
||||
hintProcessing,
|
||||
hintProcessing, hintPattern,
|
||||
hintDependency,
|
||||
hintExecuting, hintLinking,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
@@ -514,9 +516,8 @@ const
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintPath, hintConf,
|
||||
hintPath,
|
||||
hintDependency,
|
||||
hintExecuting,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
@@ -527,6 +528,8 @@ const
|
||||
InvalidFileIDX* = int32(-1)
|
||||
|
||||
var
|
||||
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
|
||||
hintQuitCalled, hintExecuting}
|
||||
filenameToIndexTbl = initTable[string, int32]()
|
||||
fileInfos*: seq[TFileInfo] = @[]
|
||||
systemFileIdx*: int32
|
||||
@@ -561,6 +564,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
let fileName = projPath.extractFilename
|
||||
result.shortName = fileName.changeFileExt("")
|
||||
result.quotedName = fileName.makeCString
|
||||
result.quotedFullName = fullPath.makeCString
|
||||
if optEmbedOrigSrc in gGlobalOptions or true:
|
||||
result.lines = @[]
|
||||
|
||||
@@ -616,6 +620,7 @@ var
|
||||
gHintCounter*: int = 0
|
||||
gWarnCounter*: int = 0
|
||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
|
||||
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
@@ -755,7 +760,7 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) =
|
||||
flushFile(stderr)
|
||||
|
||||
macro callIgnoringStyle(theProc: typed, first: typed,
|
||||
args: varargs[expr]): stmt =
|
||||
args: varargs[typed]): untyped =
|
||||
let typForegroundColor = bindSym"ForegroundColor".getType
|
||||
let typBackgroundColor = bindSym"BackgroundColor".getType
|
||||
let typStyle = bindSym"Style".getType
|
||||
@@ -772,7 +777,7 @@ macro callIgnoringStyle(theProc: typed, first: typed,
|
||||
typ != typTerminalCmd:
|
||||
result.add(arg)
|
||||
|
||||
macro callStyledWriteLineStderr(args: varargs[expr]): stmt =
|
||||
macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
|
||||
result = newCall(bindSym"styledWriteLine")
|
||||
result.add(bindSym"stderr")
|
||||
for arg in children(args[0][1]):
|
||||
@@ -784,7 +789,7 @@ template callWritelnHook(args: varargs[string, `$`]) =
|
||||
s.add arg
|
||||
writelnHook s
|
||||
|
||||
template styledMsgWriteln*(args: varargs[expr]) =
|
||||
template styledMsgWriteln*(args: varargs[typed]) =
|
||||
if not isNil(writelnHook):
|
||||
callIgnoringStyle(callWritelnHook, nil, args)
|
||||
elif optStdout in gGlobalOptions:
|
||||
@@ -995,11 +1000,11 @@ proc internalError*(errMsg: string) =
|
||||
writeContext(unknownLineInfo())
|
||||
rawMessage(errInternal, errMsg)
|
||||
|
||||
template assertNotNil*(e: expr): expr =
|
||||
template assertNotNil*(e): untyped =
|
||||
if e == nil: internalError($instantiationInfo())
|
||||
e
|
||||
|
||||
template internalAssert*(e: bool): stmt =
|
||||
template internalAssert*(e: bool) =
|
||||
if not e: internalError($instantiationInfo())
|
||||
|
||||
proc addSourceLine*(fileIdx: int32, line: string) =
|
||||
@@ -1022,7 +1027,10 @@ proc sourceLine*(i: TLineInfo): Rope =
|
||||
|
||||
proc quotedFilename*(i: TLineInfo): Rope =
|
||||
internalAssert i.fileIndex >= 0
|
||||
result = fileInfos[i.fileIndex].quotedName
|
||||
if optExcessiveStackTrace in gGlobalOptions:
|
||||
result = fileInfos[i.fileIndex].quotedFullName
|
||||
else:
|
||||
result = fileInfos[i.fileIndex].quotedName
|
||||
|
||||
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
||||
case err
|
||||
|
||||
@@ -7,7 +7,7 @@ path:"$projectPath/.."
|
||||
path:"$lib/packages/docutils"
|
||||
|
||||
define:booting
|
||||
import:testability
|
||||
#import:"$projectpath/testability"
|
||||
|
||||
@if windows:
|
||||
cincludes: "$lib/wrappers/libffi/common"
|
||||
|
||||
@@ -56,12 +56,12 @@ proc handleCmdLine() =
|
||||
loadConfigs(DefaultConfig) # load all config files
|
||||
let scriptFile = gProjectFull.changeFileExt("nims")
|
||||
if fileExists(scriptFile):
|
||||
runNimScript(scriptFile)
|
||||
runNimScript(scriptFile, freshDefines=false)
|
||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||
if scriptFile == gProjectFull: return
|
||||
elif fileExists(gProjectPath / "config.nims"):
|
||||
# directory wide NimScript file
|
||||
runNimScript(gProjectPath / "config.nims")
|
||||
runNimScript(gProjectPath / "config.nims", freshDefines=false)
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
extccomp.initVars()
|
||||
|
||||
@@ -5,7 +5,7 @@ hint[XDeclaredButNotUsed]:off
|
||||
path:"$projectPath/.."
|
||||
|
||||
path:"$lib/packages/docutils"
|
||||
path:"../../compiler"
|
||||
path:"$nim"
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
symbol:nimfix
|
||||
|
||||
@@ -66,7 +66,7 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||
]:
|
||||
result.add s[i]
|
||||
else:
|
||||
result.add toUpper(s[i])
|
||||
result.add toUpperAscii(s[i])
|
||||
of skConst, skEnumField:
|
||||
# for 'const' we keep how it's spelt; either upper case or lower case:
|
||||
result.add s[0]
|
||||
@@ -74,7 +74,7 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||
# as a special rule, don't transform 'L' to 'l'
|
||||
if s.len == 1 and s[0] == 'L': result.add 'L'
|
||||
elif '_' in s: result.add(s[i])
|
||||
else: result.add toLower(s[0])
|
||||
else: result.add toLowerAscii(s[0])
|
||||
inc i
|
||||
while i < s.len:
|
||||
if s[i] == '_':
|
||||
@@ -85,9 +85,9 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||
result.add s[i]
|
||||
else:
|
||||
inc i
|
||||
result.add toUpper(s[i])
|
||||
result.add toUpperAscii(s[i])
|
||||
elif allUpper:
|
||||
result.add toLower(s[i])
|
||||
result.add toLowerAscii(s[i])
|
||||
else:
|
||||
result.add s[i]
|
||||
inc i
|
||||
|
||||
@@ -121,7 +121,7 @@ proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
e = b
|
||||
inc(e)
|
||||
|
||||
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
|
||||
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
|
||||
var x, y: TBitSet
|
||||
toBitSet(a, x)
|
||||
toBitSet(b, y)
|
||||
|
||||
@@ -67,6 +67,8 @@ type # please make sure we have under 32 options
|
||||
optIdeDebug # idetools: debug mode
|
||||
optIdeTerse # idetools: use terse descriptions
|
||||
optNoCppExceptions # use C exception handling even with CPP
|
||||
optExcessiveStackTrace # fully qualified module filenames
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
TCommands* = enum # Nim's commands
|
||||
# **keep binary compatible**
|
||||
@@ -127,10 +129,10 @@ var
|
||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
||||
|
||||
template compilationCachePresent*: expr =
|
||||
template compilationCachePresent*: untyped =
|
||||
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
|
||||
|
||||
template optPreserveOrigSource*: expr =
|
||||
template optPreserveOrigSource*: untyped =
|
||||
optEmbedOrigSrc in gGlobalOptions
|
||||
|
||||
const
|
||||
@@ -149,6 +151,7 @@ const
|
||||
var
|
||||
gConfigVars* = newStringTable(modeStyleInsensitive)
|
||||
gDllOverrides = newStringTable(modeCaseInsensitive)
|
||||
gModuleOverrides* = newStringTable(modeStyleInsensitive)
|
||||
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
|
||||
libpath* = ""
|
||||
gProjectName* = "" # holds a name like 'nim'
|
||||
@@ -209,9 +212,7 @@ proc setDefaultLibpath*() =
|
||||
|
||||
# Special rule to support other tools (nimble) which import the compiler
|
||||
# modules and make use of them.
|
||||
let realNimPath = # Make sure we expand the symlink
|
||||
if symlinkExists(findExe("nim")): expandSymlink(findExe("nim"))
|
||||
else: findExe("nim")
|
||||
let realNimPath = findExe("nim")
|
||||
# Find out if $nim/../../lib/system.nim exists.
|
||||
let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
|
||||
if not fileExists(libpath / "system.nim") and
|
||||
@@ -219,7 +220,7 @@ proc setDefaultLibpath*() =
|
||||
libpath = parentNimLibPath
|
||||
|
||||
proc canonicalizePath*(path: string): string =
|
||||
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
|
||||
when not FileSystemCaseSensitive: result = path.expandFilename.toLowerAscii
|
||||
else: result = path.expandFilename
|
||||
|
||||
proc shortenDir*(dir: string): string =
|
||||
@@ -238,57 +239,26 @@ proc removeTrailingDirSep*(path: string): string =
|
||||
else:
|
||||
result = path
|
||||
|
||||
include packagehandling
|
||||
|
||||
proc getNimcacheDir*: string =
|
||||
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
|
||||
genSubDir
|
||||
|
||||
template newPackageCache(): expr =
|
||||
newStringTable(when FileSystemCaseSensitive:
|
||||
modeCaseInsensitive
|
||||
else:
|
||||
modeCaseSensitive)
|
||||
|
||||
var packageCache = newPackageCache()
|
||||
|
||||
proc resetPackageCache*() = packageCache = newPackageCache()
|
||||
|
||||
iterator myParentDirs(p: string): string =
|
||||
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
|
||||
var current = p
|
||||
while true:
|
||||
current = current.parentDir
|
||||
if current.len == 0: break
|
||||
yield current
|
||||
|
||||
proc getPackageName*(path: string): string =
|
||||
var parents = 0
|
||||
block packageSearch:
|
||||
for d in myParentDirs(path):
|
||||
if packageCache.hasKey(d):
|
||||
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
|
||||
return packageCache[d]
|
||||
inc parents
|
||||
for file in walkFiles(d / "*.nimble"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
for file in walkFiles(d / "*.babel"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
# we also store if we didn't find anything:
|
||||
if result.isNil: result = ""
|
||||
for d in myParentDirs(path):
|
||||
#echo "set cache ", d, " |", result, "|", parents
|
||||
packageCache[d] = result
|
||||
dec parents
|
||||
if parents <= 0: break
|
||||
|
||||
proc withPackageName*(path: string): string =
|
||||
let x = path.getPackageName
|
||||
if x.len == 0:
|
||||
result = path
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
result = (p / (x & '_' & file)) & ext
|
||||
proc pathSubs*(p, config: string): string =
|
||||
let home = removeTrailingDirSep(os.getHomeDir())
|
||||
result = unixToNativePath(p % [
|
||||
"nim", getPrefixDir(),
|
||||
"lib", libpath,
|
||||
"home", home,
|
||||
"config", config,
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath,
|
||||
"projectdir", options.gProjectPath,
|
||||
"nimcache", getNimcacheDir()])
|
||||
if '~' in result:
|
||||
result = result.replace("~", home)
|
||||
|
||||
proc toGeneratedFile*(path, ext: string): string =
|
||||
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||
@@ -357,17 +327,25 @@ proc rawFindFile2(f: string): string =
|
||||
it = PStrEntry(it.next)
|
||||
result = ""
|
||||
|
||||
template patchModule() {.dirty.} =
|
||||
if result.len > 0 and gModuleOverrides.len > 0:
|
||||
let key = getPackageName(result) & "_" & splitFile(result).name
|
||||
if gModuleOverrides.hasKey(key):
|
||||
let ov = gModuleOverrides[key]
|
||||
if ov.len > 0: result = ov
|
||||
|
||||
proc findFile*(f: string): string {.procvar.} =
|
||||
if f.isAbsolute:
|
||||
result = if f.existsFile: f else: ""
|
||||
else:
|
||||
result = f.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile
|
||||
result = f.toLowerAscii.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.rawFindFile2
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile2
|
||||
result = f.toLowerAscii.rawFindFile2
|
||||
patchModule()
|
||||
|
||||
proc findModule*(modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
@@ -386,6 +364,7 @@ proc findModule*(modulename, currentModule: string): string =
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = findFile(m)
|
||||
patchModule()
|
||||
|
||||
proc libCandidates*(s: string, dest: var seq[string]) =
|
||||
var le = strutils.find(s, '(')
|
||||
@@ -426,10 +405,10 @@ proc binaryStrSearch*(x: openArray[string], y: string): int =
|
||||
return mid
|
||||
result = - 1
|
||||
|
||||
template nimdbg*: expr = c.module.fileIdx == gProjectMainIdx
|
||||
template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
|
||||
template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
|
||||
template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
|
||||
template nimdbg*: untyped = c.module.fileIdx == gProjectMainIdx
|
||||
template cnimdbg*: untyped = p.module.module.fileIdx == gProjectMainIdx
|
||||
template pnimdbg*: untyped = p.lex.fileIdx == gProjectMainIdx
|
||||
template lnimdbg*: untyped = L.fileIdx == gProjectMainIdx
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
|
||||
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`
|
||||
parMessage(p, msg, prettyTok(tok))
|
||||
|
||||
template withInd(p: expr, body: stmt) {.immediate.} =
|
||||
template withInd(p, body: untyped) =
|
||||
let oldInd = p.currInd
|
||||
p.currInd = p.tok.indent
|
||||
body
|
||||
@@ -202,7 +202,7 @@ proc isRightAssociative(tok: TToken): bool {.inline.} =
|
||||
|
||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
## Calculates the precedence of the given token.
|
||||
template considerStrongSpaces(x): expr =
|
||||
template considerStrongSpaces(x): untyped =
|
||||
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
|
||||
|
||||
case tok.tokType
|
||||
@@ -214,7 +214,7 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
if L > 1 and tok.ident.s[L-1] == '>' and
|
||||
tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
|
||||
|
||||
template considerAsgn(value: expr) =
|
||||
template considerAsgn(value: untyped) =
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: value
|
||||
|
||||
case relevantChar
|
||||
@@ -326,6 +326,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
eat(p, tkAccent)
|
||||
else:
|
||||
if allowNil and p.tok.tokType == tkNil:
|
||||
@@ -685,11 +686,19 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
#| | '{' optInd indexExprList optPar '}'
|
||||
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
|
||||
result = r
|
||||
|
||||
template somePar() =
|
||||
if p.tok.strongSpaceA > 0:
|
||||
if p.strongSpaces:
|
||||
break
|
||||
else:
|
||||
parMessage(p, warnDeprecated,
|
||||
"a [b] will be parsed as command syntax; spacing")
|
||||
while p.tok.indent < 0 or
|
||||
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
|
||||
case p.tok.tokType
|
||||
of tkParLe:
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
somePar()
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
||||
result.kind = nkObjConstr
|
||||
@@ -704,10 +713,10 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
result = dotExpr(p, result)
|
||||
result = parseGStrLit(p, result)
|
||||
of tkBracketLe:
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
somePar()
|
||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkCurlyLe:
|
||||
if p.strongSpaces and p.tok.strongSpaceA > 0: break
|
||||
somePar()
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
|
||||
if p.inPragma == 0:
|
||||
@@ -963,8 +972,9 @@ proc parseDoBlock(p: var TParser): PNode =
|
||||
proc parseDoBlocks(p: var TParser, call: PNode) =
|
||||
#| doBlocks = doBlock ^* IND{=}
|
||||
if p.tok.tokType == tkDo:
|
||||
addSon(call, parseDoBlock(p))
|
||||
while sameInd(p) and p.tok.tokType == tkDo:
|
||||
#withInd(p):
|
||||
# addSon(call, parseDoBlock(p))
|
||||
while sameOrNoInd(p) and p.tok.tokType == tkDo:
|
||||
addSon(call, parseDoBlock(p))
|
||||
|
||||
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
|
||||
|
||||
@@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
|
||||
# system.nim deactivates all hints, for verbosity:3 we want the processing
|
||||
# messages nonetheless, so we activate them again unconditionally:
|
||||
incl(msgs.gNotes, hintProcessing)
|
||||
message(n.info, hintProcessing, $idgen.gBackendId)
|
||||
message(n.info, hintProcessing, $idgen.gFrontendId)
|
||||
|
||||
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||
result = matchNodeKinds(p.constraint, n)
|
||||
if not result: return
|
||||
if isNil(n.typ):
|
||||
result = p.typ.kind in {tyEmpty, tyStmt}
|
||||
result = p.typ.kind in {tyVoid, tyStmt}
|
||||
else:
|
||||
result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
|
||||
|
||||
@@ -129,7 +129,7 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
||||
result = bindOrCheck(c, p.sons[2].sym, arglist)
|
||||
|
||||
proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
# hidden conversions (?)
|
||||
let n = skipHidden(n)
|
||||
if nfNoRewrite in n.flags:
|
||||
result = false
|
||||
elif isPatternParam(c, p):
|
||||
|
||||
@@ -159,7 +159,7 @@ type
|
||||
# alias conditionals to condsyms (end of module).
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
|
||||
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430
|
||||
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430, cpuSparc64
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
@@ -187,7 +187,8 @@ const
|
||||
(name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
|
||||
(name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
|
||||
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
|
||||
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
|
||||
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64)]
|
||||
|
||||
var
|
||||
targetCPU*, hostCPU*: TSystemCPU
|
||||
|
||||
@@ -63,11 +63,12 @@ const
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims}
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
|
||||
wIntDefine, wStrDefine}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||
allRoutinePragmas* = methodPragmas + iteratorPragmas + lambdaPragmas
|
||||
|
||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||
# implementation
|
||||
@@ -89,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
else:
|
||||
invalidPragma(it)
|
||||
|
||||
proc setExternName(s: PSym, extname: string) =
|
||||
s.loc.r = rope(extname % s.name.s)
|
||||
proc setExternName(s: PSym, extname: string, info: TLineInfo) =
|
||||
# special cases to improve performance:
|
||||
if extname == "$1":
|
||||
s.loc.r = rope(s.name.s)
|
||||
elif '$' notin extname:
|
||||
s.loc.r = rope(extname)
|
||||
else:
|
||||
try:
|
||||
s.loc.r = rope(extname % s.name.s)
|
||||
except ValueError:
|
||||
localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
||||
if gCmd == cmdPretty and '$' notin extname:
|
||||
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
|
||||
s.loc.flags.incl(lfFullExternalName)
|
||||
|
||||
proc makeExternImport(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname, info)
|
||||
incl(s.flags, sfImportc)
|
||||
excl(s.flags, sfForward)
|
||||
|
||||
proc validateExternCName(s: PSym, info: TLineInfo) =
|
||||
## Validates that the symbol name in s.loc.r is a valid C identifier.
|
||||
##
|
||||
## Valid identifiers are those alphanumeric including the underscore not
|
||||
## starting with a number. If the check fails, a generic error will be
|
||||
## displayed to the user.
|
||||
let target = $s.loc.r
|
||||
if target.len < 1 or target[0] notin IdentStartChars or
|
||||
not target.allCharsInSet(IdentChars):
|
||||
localError(info, errGenerated, "invalid exported symbol")
|
||||
|
||||
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname)
|
||||
# XXX to fix make it work with nimrtl.
|
||||
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
|
||||
# validateExternCName(s, info)
|
||||
setExternName(s, extname, info)
|
||||
incl(s.flags, sfExportc)
|
||||
|
||||
proc processImportCompilerProc(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname, info)
|
||||
incl(s.flags, sfImportc)
|
||||
excl(s.flags, sfForward)
|
||||
incl(s.loc.flags, lfImportCompilerProc)
|
||||
|
||||
proc processImportCpp(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname, info)
|
||||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfInfixCall)
|
||||
excl(s.flags, sfForward)
|
||||
@@ -133,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
extccomp.gMixedMode = true
|
||||
|
||||
proc processImportObjC(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
|
||||
setExternName(s, extname, info)
|
||||
incl(s.flags, sfImportc)
|
||||
incl(s.flags, sfNamedParamCall)
|
||||
excl(s.flags, sfForward)
|
||||
@@ -256,8 +252,9 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
if (sym == nil) or (sym.kind == skModule):
|
||||
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
|
||||
expectDynlibNode(c, n))
|
||||
let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
if not lib.isOverriden:
|
||||
POptionEntry(c.optionStack.tail).dynlib = lib
|
||||
else:
|
||||
if n.kind == nkExprColonExpr:
|
||||
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||
@@ -276,6 +273,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
proc processNote(c: PContext, n: PNode) =
|
||||
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
|
||||
(n.sons[0].kind == nkBracketExpr) and
|
||||
(n.sons[0].sons.len == 2) and
|
||||
(n.sons[0].sons[1].kind == nkIdent) and
|
||||
(n.sons[0].sons[0].kind == nkIdent):
|
||||
#and (n.sons[1].kind == nkIdent):
|
||||
@@ -391,21 +389,25 @@ type
|
||||
TLinkFeature = enum
|
||||
linkNormal, linkSys
|
||||
|
||||
proc processCompile(c: PContext, n: PNode) =
|
||||
proc relativeFile(c: PContext; n: PNode; ext=""): string =
|
||||
var s = expectStrLit(c, n)
|
||||
var found = findFile(s)
|
||||
if found == "": found = s
|
||||
var trunc = changeFileExt(found, "")
|
||||
if not isAbsolute(found):
|
||||
found = parentDir(n.info.toFullPath) / found
|
||||
if ext.len > 0 and splitFile(s).ext == "":
|
||||
s = addFileExt(s, ext)
|
||||
result = parentDir(n.info.toFullPath) / s
|
||||
if not fileExists(result):
|
||||
if isAbsolute(s): result = s
|
||||
else:
|
||||
result = findFile(s)
|
||||
if result.len == 0: result = s
|
||||
|
||||
proc processCompile(c: PContext, n: PNode) =
|
||||
let found = relativeFile(c, n)
|
||||
let trunc = found.changeFileExt("")
|
||||
extccomp.addExternalFileToCompile(found)
|
||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||
|
||||
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
|
||||
var f = expectStrLit(c, n)
|
||||
if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
|
||||
var found = findFile(f)
|
||||
if found == "": found = f # use the default
|
||||
let found = relativeFile(c, n, CC[cCompiler].objExt)
|
||||
case feature
|
||||
of linkNormal: extccomp.addFileToLink(found)
|
||||
of linkSys:
|
||||
@@ -564,7 +566,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
|
||||
localError(pragma.info, "list of key:value pairs expected"); return
|
||||
for n in pragma:
|
||||
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
|
||||
let dest = qualifiedLookUp(c, n[1])
|
||||
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
|
||||
let src = considerQuotedIdent(n[0])
|
||||
let alias = newSym(skAlias, src, dest, n[0].info)
|
||||
incl(alias.flags, sfExported)
|
||||
@@ -589,7 +591,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||
# and perform the lookup on demand instead.
|
||||
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
|
||||
else:
|
||||
result = qualifiedLookUp(c, n)
|
||||
result = qualifiedLookUp(c, n, {checkUndeclared})
|
||||
|
||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
validPragmas: TSpecialWords): bool =
|
||||
@@ -616,20 +618,23 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wExportc:
|
||||
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
|
||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wImportCompilerProc:
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
|
||||
of wExtern: setExternName(sym, expectStrLit(c, it))
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
|
||||
of wImmediate:
|
||||
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
|
||||
if sym.kind in {skTemplate, skMacro}:
|
||||
incl(sym.flags, sfImmediate)
|
||||
incl(sym.flags, sfAllUntyped)
|
||||
message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate")
|
||||
else: invalidPragma(it)
|
||||
of wDirty:
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||
else: invalidPragma(it)
|
||||
of wImportCpp:
|
||||
processImportCpp(sym, getOptionalStr(c, it, "$1"))
|
||||
processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wImportObjC:
|
||||
processImportObjC(sym, getOptionalStr(c, it, "$1"))
|
||||
processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
of wAlign:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var align = expectIntLit(c, it)
|
||||
@@ -894,6 +899,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
of wBase:
|
||||
noVal(it)
|
||||
sym.flags.incl sfBase
|
||||
of wIntDefine:
|
||||
sym.magic = mIntDefine
|
||||
of wStrDefine:
|
||||
sym.magic = mStrDefine
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
|
||||
|
||||
@@ -704,7 +704,10 @@ proc gcase(g: var TSrcGen, n: PNode) =
|
||||
proc gproc(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
|
||||
let s = n.sons[namePos].sym
|
||||
put(g, tkSymbol, renderDefinitionName(s))
|
||||
if sfGenSym in s.flags:
|
||||
put(g, tkIntLit, $s.id)
|
||||
else:
|
||||
gsub(g, n.sons[namePos])
|
||||
|
||||
@@ -712,7 +715,11 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
||||
gpattern(g, n.sons[patternPos])
|
||||
let oldCheckAnon = g.checkAnon
|
||||
g.checkAnon = true
|
||||
gsub(g, n.sons[genericParamsPos])
|
||||
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
|
||||
n[miscPos][1].kind != nkEmpty:
|
||||
gsub(g, n[miscPos][1])
|
||||
else:
|
||||
gsub(g, n.sons[genericParamsPos])
|
||||
g.checkAnon = oldCheckAnon
|
||||
gsub(g, n.sons[paramsPos])
|
||||
gsub(g, n.sons[pragmasPos])
|
||||
@@ -794,7 +801,8 @@ proc gident(g: var TSrcGen, n: PNode) =
|
||||
else:
|
||||
t = tkOpr
|
||||
put(g, t, s)
|
||||
if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
|
||||
if n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags):
|
||||
put(g, tkIntLit, $n.sym.id)
|
||||
|
||||
proc doParamsAux(g: var TSrcGen, params: PNode) =
|
||||
if params.len > 1:
|
||||
@@ -802,7 +810,7 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
|
||||
gsemicolon(g, params, 1)
|
||||
put(g, tkParRi, ")")
|
||||
|
||||
if params.sons[0].kind != nkEmpty:
|
||||
if params.len > 0 and params.sons[0].kind != nkEmpty:
|
||||
putWithSpace(g, tkOpr, "->")
|
||||
gsub(g, params.sons[0])
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ proc toStrMaxPrecision*(f: BiggestFloat): string =
|
||||
if f > 0.0: result = "INF"
|
||||
else: result = "-INF"
|
||||
else:
|
||||
var buf: array [0..80, char]
|
||||
var buf: array[0..80, char]
|
||||
c_sprintf(buf, "%#.16e", f)
|
||||
result = $buf
|
||||
|
||||
@@ -64,7 +64,7 @@ const
|
||||
const
|
||||
vintDelta = 5
|
||||
|
||||
template encodeIntImpl(self: expr) =
|
||||
template encodeIntImpl(self) =
|
||||
var d: char
|
||||
var v = x
|
||||
var rem = v mod 190
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
|
||||
os, times, osproc
|
||||
os, times, osproc, wordrecg, strtabs
|
||||
|
||||
# we support 'cmpIgnoreStyle' natively for efficiency:
|
||||
from strutils import cmpIgnoreStyle
|
||||
from strutils import cmpIgnoreStyle, contains
|
||||
|
||||
proc listDirs(a: VmArgs, filter: set[PathComponent]) =
|
||||
let dir = getString(a, 0)
|
||||
@@ -116,12 +116,27 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
|
||||
setResult(a, options.command)
|
||||
cbconf switch:
|
||||
processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
|
||||
cbconf hintImpl:
|
||||
processSpecificNote(a.getString 0, wHint, passPP, unknownLineInfo(),
|
||||
a.getString 1)
|
||||
cbconf warningImpl:
|
||||
processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(),
|
||||
a.getString 1)
|
||||
cbconf patchFile:
|
||||
let key = a.getString(0) & "_" & a.getString(1)
|
||||
var val = a.getString(2).addFileExt(NimExt)
|
||||
if {'$', '~'} in val:
|
||||
val = pathSubs(val, vthisDir)
|
||||
elif not isAbsolute(val):
|
||||
val = vthisDir / val
|
||||
gModuleOverrides[key] = val
|
||||
cbconf selfExe:
|
||||
setResult(a, os.getAppFilename())
|
||||
|
||||
|
||||
proc runNimScript*(scriptName: string) =
|
||||
proc runNimScript*(scriptName: string; freshDefines=true) =
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
initDefines()
|
||||
if freshDefines: initDefines()
|
||||
|
||||
defineSymbol("nimscript")
|
||||
defineSymbol("nimconfig")
|
||||
|
||||
@@ -59,21 +59,11 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
||||
# templates perform some quick check whether the cursor is actually in
|
||||
# the generic or template.
|
||||
when defined(nimsuggest):
|
||||
assert gCmd == cmdIdeTools
|
||||
if requiresCheck:
|
||||
if gCmd == cmdIdeTools and requiresCheck:
|
||||
#if optIdeDebug in gGlobalOptions:
|
||||
# echo "passing to safeSemExpr: ", renderTree(n)
|
||||
discard safeSemExpr(c, n)
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
let named = typeToString(formal)
|
||||
let desc = typeToString(formal, preferDesc)
|
||||
let x = if named == desc: named else: named & " = " & desc
|
||||
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [x]))
|
||||
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
if arg.typ.isNil:
|
||||
localError(arg.info, errExprXHasNoType,
|
||||
@@ -174,7 +164,7 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
||||
|
||||
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLower
|
||||
proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii
|
||||
|
||||
# like newSymS, but considers gensym'ed symbols
|
||||
if n.kind == nkSym:
|
||||
@@ -316,6 +306,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
|
||||
include hlo, seminst, semcall
|
||||
|
||||
when false:
|
||||
# hopefully not required:
|
||||
proc resetSemFlag(n: PNode) =
|
||||
excl n.flags, nfSem
|
||||
for i in 0 ..< n.safeLen:
|
||||
resetSemFlag(n[i])
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
## Semantically check the output of a macro.
|
||||
@@ -329,6 +326,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
c.friendModules.add(s.owner.getModule)
|
||||
|
||||
result = n
|
||||
excl(n.flags, nfSem)
|
||||
#resetSemFlag n
|
||||
if s.typ.sons[0] == nil:
|
||||
result = semStmt(c, result)
|
||||
else:
|
||||
@@ -363,7 +362,6 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
|
||||
#if c.evalContext == nil:
|
||||
# c.evalContext = c.createEvalContext(emStatic)
|
||||
|
||||
result = evalMacroCall(c.module, n, nOrig, sym)
|
||||
if efNoSemCheck notin flags:
|
||||
result = semAfterMacroCall(c, result, sym, flags)
|
||||
@@ -419,17 +417,42 @@ proc myOpen(module: PSym): PPassContext =
|
||||
c.importTable.addSym(module) # a module knows itself
|
||||
if sfSystemModule in module.flags:
|
||||
magicsys.systemModule = module # set global variable!
|
||||
else:
|
||||
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
||||
importAllSymbols(c, magicsys.systemModule)
|
||||
c.topLevelScope = openScope(c)
|
||||
# don't be verbose unless the module belongs to the main package:
|
||||
if module.owner.id == gMainPackageId:
|
||||
gNotes = gMainPackageNotes
|
||||
else:
|
||||
if gMainPackageNotes == {}: gMainPackageNotes = gNotes
|
||||
gNotes = ForeignPackageNotes
|
||||
result = c
|
||||
|
||||
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||
result = myOpen(module)
|
||||
for m in items(rd.methods): methodDef(m, true)
|
||||
|
||||
proc isImportSystemStmt(n: PNode): bool =
|
||||
if magicsys.systemModule == nil: return false
|
||||
case n.kind
|
||||
of nkImportStmt:
|
||||
for x in n:
|
||||
let f = checkModuleName(x)
|
||||
if f == magicsys.systemModule.info.fileIndex:
|
||||
return true
|
||||
of nkImportExceptStmt, nkFromStmt:
|
||||
let f = checkModuleName(n[0])
|
||||
if f == magicsys.systemModule.info.fileIndex:
|
||||
return true
|
||||
else: discard
|
||||
|
||||
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
if c.topStmts == 0 and not isImportSystemStmt(n):
|
||||
if sfSystemModule notin c.module.flags and
|
||||
n.kind notin {nkEmpty, nkCommentStmt}:
|
||||
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
||||
importAllSymbols(c, magicsys.systemModule)
|
||||
inc c.topStmts
|
||||
else:
|
||||
inc c.topStmts
|
||||
if sfNoForward in c.module.flags:
|
||||
result = semAllTypeSections(c, n)
|
||||
else:
|
||||
|
||||
@@ -183,7 +183,7 @@ proc newSeqCall(c: PContext; x, y: PNode): PNode =
|
||||
|
||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
of tyNone, tyEmpty: discard
|
||||
of tyNone, tyEmpty, tyVoid: discard
|
||||
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
|
||||
tyPtr, tyString, tyRef:
|
||||
defaultOp(c, t, body, x, y)
|
||||
|
||||
@@ -53,7 +53,18 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
if symx.kind in filter:
|
||||
syms.add((symx, o.lastOverloadScope))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if syms.len == 0: return
|
||||
if syms.len == 0:
|
||||
when false:
|
||||
if skIterator notin filter:
|
||||
# also try iterators, but these are 2nd class:
|
||||
symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
if symx.kind == skIterator:
|
||||
syms.add((symx, 100))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if syms.len == 0: return
|
||||
else:
|
||||
return
|
||||
|
||||
var z: TCandidate
|
||||
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
||||
@@ -69,7 +80,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
errors.safeAdd((sym, int z.mutabilityProblem))
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
@@ -111,7 +122,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
|
||||
var prefer = preferName
|
||||
for err in errors:
|
||||
for err, mut in items(errors):
|
||||
var errProto = ""
|
||||
let n = err.typ.n
|
||||
for i in countup(1, n.len - 1):
|
||||
@@ -123,14 +134,21 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
if errProto == proto:
|
||||
prefer = preferModuleInfo
|
||||
break
|
||||
|
||||
# now use the information stored in 'prefer' to produce a nice error message:
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1, prefer))
|
||||
add(result, ')')
|
||||
var candidates = ""
|
||||
for err in errors:
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
for err, mut in items(errors):
|
||||
if err.kind in routineKinds and err.ast != nil:
|
||||
add(candidates, renderTree(err.ast,
|
||||
{renderNoBody, renderNoComments,renderNoPragmas}))
|
||||
else:
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
if mut != 0 and mut < n.len:
|
||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n")
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
|
||||
@@ -138,6 +156,20 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
else:
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
var errors: CandidateErrors = @[]
|
||||
var o: TOverloadIter
|
||||
let headSymbol = n[0]
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
if symx.kind in routineKinds:
|
||||
errors.add((symx, 0))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if errors.len == 0:
|
||||
localError(n.info, "could not resolve: " & $n)
|
||||
else:
|
||||
notFoundError(c, n, errors)
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds;
|
||||
errors: var CandidateErrors): TCandidate =
|
||||
@@ -154,8 +186,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
template pickBest(headSymbol) =
|
||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||
filter, result, alt, errors)
|
||||
|
||||
|
||||
pickBest(f)
|
||||
|
||||
let overloadsState = result.state
|
||||
@@ -226,7 +256,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
#notFoundError(c, n, errors)
|
||||
|
||||
return
|
||||
|
||||
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
|
||||
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
|
||||
internalAssert result.state == csMatch
|
||||
@@ -295,8 +324,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
var finalCallee = x.calleeSym
|
||||
markUsed(n.sons[0].info, finalCallee)
|
||||
styleCheckUse(n.sons[0].info, finalCallee)
|
||||
if finalCallee.ast == nil:
|
||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||
assert finalCallee.ast != nil
|
||||
if x.hasFauxMatch:
|
||||
result = x.call
|
||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||
@@ -315,12 +343,12 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
# are added as normal params.
|
||||
for s in instantiateGenericParamList(c, gp, x.bindings):
|
||||
case s.kind
|
||||
of skConst:
|
||||
x.call.add s.ast
|
||||
of skType:
|
||||
x.call.add newSymNode(s, n.info)
|
||||
else:
|
||||
internalAssert false
|
||||
of skConst:
|
||||
x.call.add s.ast
|
||||
of skType:
|
||||
x.call.add newSymNode(s, n.info)
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
@@ -361,7 +389,14 @@ proc explicitGenericInstError(n: PNode): PNode =
|
||||
|
||||
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, s, n)
|
||||
# binding has to stay 'nil' for this to work!
|
||||
initCandidate(c, m, s, nil)
|
||||
|
||||
for i in 1..sonsLen(n)-1:
|
||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||
let arg = n[i].typ
|
||||
let tm = typeRel(m, formal, arg, true)
|
||||
if tm in {isNone, isConvertible}: return nil
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
@@ -382,6 +417,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
|
||||
return n
|
||||
result = explicitGenericSym(c, n, s)
|
||||
if result == nil: result = explicitGenericInstError(n)
|
||||
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
||||
# choose the generic proc with the proper number of type parameters.
|
||||
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
|
||||
@@ -394,11 +430,12 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
# it suffices that the candidate has the proper number of generic
|
||||
# type parameters:
|
||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||
result.add(explicitGenericSym(c, n, candidate))
|
||||
let x = explicitGenericSym(c, n, candidate)
|
||||
if x != nil: result.add(x)
|
||||
# get rid of nkClosedSymChoice if not ambiguous:
|
||||
if result.len == 1 and a.kind == nkClosedSymChoice:
|
||||
result = result[0]
|
||||
# candidateCount != 1: return explicitGenericInstError(n)
|
||||
elif result.len == 0: result = explicitGenericInstError(n)
|
||||
else:
|
||||
result = explicitGenericInstError(n)
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ type
|
||||
efLValue, efWantIterator, efInTypeof,
|
||||
efWantStmt, efAllowStmt, efDetermineType,
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
|
||||
efNoProcvarCheck
|
||||
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
TTypeAttachedOp* = enum
|
||||
@@ -99,11 +99,12 @@ type
|
||||
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
|
||||
# naming it multiple times
|
||||
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
|
||||
topStmts*: int # counts the number of encountered top level statements
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||
inParallelStmt*: int
|
||||
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
op: TTypeAttachedOp): PSym {.nimcall.}
|
||||
op: TTypeAttachedOp; col: int): PSym {.nimcall.}
|
||||
selfName*: PIdent
|
||||
signatures*: TStrTable
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||
result = nil
|
||||
|
||||
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
|
||||
template maybeAddLine(e: expr): stmt =
|
||||
template maybeAddLine(e) =
|
||||
let stmt = e
|
||||
if stmt != nil:
|
||||
if result == nil: result = newNode(nkStmtList)
|
||||
@@ -139,6 +139,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
||||
t = t.skipTypes({tyGenericInst})
|
||||
case t.kind
|
||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
|
||||
t.destructor = analyzingDestructor
|
||||
if instantiateDestructor(c, t.sons[0]) != nil:
|
||||
t.destructor = getCompilerProc"nimDestroyRange"
|
||||
return t
|
||||
|
||||
@@ -15,7 +15,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
pushInfoContext(n.info)
|
||||
result = evalTemplate(n, s, getCurrOwner())
|
||||
result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
||||
popInfoContext()
|
||||
|
||||
@@ -24,16 +24,15 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# same as 'semExprWithType' but doesn't check for proc vars
|
||||
result = semExpr(c, n, flags + {efOperand})
|
||||
if result.kind == nkEmpty and result.typ.isNil:
|
||||
#if result.kind == nkEmpty and result.typ.isNil:
|
||||
# do not produce another redundant error message:
|
||||
#raiseRecoverableError("")
|
||||
result = errorNode(c, n)
|
||||
# result = errorNode(c, n)
|
||||
if result.typ != nil:
|
||||
# XXX tyGenericInst here?
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyEmpty, c)
|
||||
result.typ.flags.incl tfVoid
|
||||
result.typ = newTypeS(tyVoid, c)
|
||||
else:
|
||||
localError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
@@ -51,7 +50,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
else:
|
||||
# XXX tyGenericInst here?
|
||||
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
semDestructorCheck(c, result, flags)
|
||||
@@ -74,8 +72,12 @@ proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
|
||||
proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
|
||||
result = copyTree(s.ast)
|
||||
result.typ = s.typ
|
||||
result.info = n.info
|
||||
if result.isNil:
|
||||
localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
|
||||
result = newSymNode(s)
|
||||
else:
|
||||
result.typ = s.typ
|
||||
result.info = n.info
|
||||
|
||||
type
|
||||
TConvStatus = enum
|
||||
@@ -83,8 +85,9 @@ type
|
||||
convNotNeedeed,
|
||||
convNotLegal
|
||||
|
||||
proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
|
||||
return if inheritanceDiff(castDest, src) == high(int):
|
||||
proc checkConversionBetweenObjects(castDest, src: PType; pointers: int): TConvStatus =
|
||||
let diff = inheritanceDiff(castDest, src)
|
||||
return if diff == high(int) or (pointers > 1 and diff != 0):
|
||||
convNotLegal
|
||||
else:
|
||||
convOK
|
||||
@@ -101,13 +104,15 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
|
||||
return
|
||||
var d = skipTypes(castDest, abstractVar)
|
||||
var s = skipTypes(src, abstractVar-{tyTypeDesc})
|
||||
var pointers = 0
|
||||
while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
|
||||
d = d.lastSon
|
||||
s = s.lastSon
|
||||
inc pointers
|
||||
if d == nil:
|
||||
result = convNotLegal
|
||||
elif d.kind == tyObject and s.kind == tyObject:
|
||||
result = checkConversionBetweenObjects(d, s)
|
||||
result = checkConversionBetweenObjects(d, s, pointers)
|
||||
elif (skipTypes(castDest, abstractVarRange).kind in IntegralTypes) and
|
||||
(skipTypes(src, abstractVarRange-{tyTypeDesc}).kind in IntegralTypes):
|
||||
# accept conversion between integral types
|
||||
@@ -186,17 +191,17 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||
case status
|
||||
of convOK:
|
||||
# handle SomeProcType(SomeGenericProc)
|
||||
# XXX: This needs fixing. checkConvertible uses typeRel internally, but
|
||||
# doesn't bother to perform the work done in paramTypeMatchAux/fitNode
|
||||
# so we are redoing the typeRel work here. Why does semConv exist as a
|
||||
# separate proc from fitNode?
|
||||
if op.kind == nkSym and op.sym.isGenericRoutine:
|
||||
result.sons[1] = fitNode(c, result.typ, result.sons[1])
|
||||
elif op.kind == nkPar and targetType.kind == tyTuple:
|
||||
op = fitNode(c, targetType, op)
|
||||
of convNotNeedeed:
|
||||
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
|
||||
of convNotLegal:
|
||||
localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
|
||||
[op.typ.typeToString, result.typ.typeToString])
|
||||
result = fitNode(c, result.typ, result.sons[1])
|
||||
if result == nil:
|
||||
localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
|
||||
[op.typ.typeToString, result.typ.typeToString])
|
||||
else:
|
||||
for i in countup(0, sonsLen(op) - 1):
|
||||
let it = op.sons[i]
|
||||
@@ -206,7 +211,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||
styleCheckUse(n.info, it.sym)
|
||||
markIndirect(c, it.sym)
|
||||
return it
|
||||
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
|
||||
errorUseQualifier(c, n.info, op.sons[0].sym)
|
||||
|
||||
proc semCast(c: PContext, n: PNode): PNode =
|
||||
## Semantically analyze a casting ("cast[type](param)")
|
||||
@@ -594,6 +599,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
|
||||
var callee = n.sons[0].sym
|
||||
# workaround for bug #537 (overly aggressive inlining leading to
|
||||
# wrong NimNode semantics):
|
||||
if n.typ != nil and tfTriggersCompileTime in n.typ.flags: return
|
||||
|
||||
# constant folding that is necessary for correctness of semantic pass:
|
||||
if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
|
||||
@@ -710,25 +718,60 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
||||
initCandidate(c, result, t)
|
||||
matches(c, n, nOrig, result)
|
||||
|
||||
proc bracketedMacro(n: PNode): PSym =
|
||||
if n.len >= 1 and n[0].kind == nkSym:
|
||||
result = n[0].sym
|
||||
if result.kind notin {skMacro, skTemplate}:
|
||||
result = nil
|
||||
|
||||
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
|
||||
flags: TExprFlags): PNode =
|
||||
# We received untransformed bracket expression coming from macroOrTmpl[].
|
||||
# Transform it to macro or template call, where first come normal
|
||||
# arguments, next come generic template arguments.
|
||||
var sons = newSeq[PNode]()
|
||||
sons.add inner.sons[0]
|
||||
# Normal arguments:
|
||||
for i in 1..<outer.len:
|
||||
sons.add outer.sons[i]
|
||||
# Generic template arguments from bracket expression:
|
||||
for i in 1..<inner.len:
|
||||
sons.add inner.sons[i]
|
||||
shallowCopy(outer.sons, sons)
|
||||
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
|
||||
# However passing to semDirectOp doesn't work here.
|
||||
case s.kind
|
||||
of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, outer, s, flags)
|
||||
else: assert(false)
|
||||
return
|
||||
|
||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = nil
|
||||
checkMinSonsLen(n, 1)
|
||||
var prc = n.sons[0]
|
||||
if n.sons[0].kind == nkDotExpr:
|
||||
checkSonsLen(n.sons[0], 2)
|
||||
n.sons[0] = semFieldAccess(c, n.sons[0])
|
||||
if n.sons[0].kind == nkDotCall:
|
||||
let n0 = semFieldAccess(c, n.sons[0])
|
||||
if n0.kind == nkDotCall:
|
||||
# it is a static call!
|
||||
result = n.sons[0]
|
||||
result = n0
|
||||
result.kind = nkCall
|
||||
result.flags.incl nfExplicitCall
|
||||
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||
return semExpr(c, result, flags)
|
||||
else:
|
||||
n.sons[0] = n0
|
||||
else:
|
||||
n.sons[0] = semExpr(c, n.sons[0])
|
||||
n.sons[0] = semExpr(c, n.sons[0], {efInCall})
|
||||
let t = n.sons[0].typ
|
||||
if t != nil and t.kind == tyVar:
|
||||
n.sons[0] = newDeref(n.sons[0])
|
||||
elif n.sons[0].kind == nkBracketExpr:
|
||||
let s = bracketedMacro(n.sons[0])
|
||||
if s != nil:
|
||||
return semBracketedMacro(c, n, n.sons[0], s, flags)
|
||||
|
||||
let nOrig = n.copyTree
|
||||
semOpAux(c, n)
|
||||
var t: PType = nil
|
||||
@@ -958,8 +1001,20 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
else: result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||
of skMacro:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate:
|
||||
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skParam:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
@@ -1011,8 +1066,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = makeTypeDesc(c, s.typ)
|
||||
of skField:
|
||||
if c.p != nil and c.p.selfSym != nil:
|
||||
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
var p = c.p
|
||||
while p != nil and p.selfSym == nil:
|
||||
p = p.next
|
||||
if p != nil and p.selfSym != nil:
|
||||
var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
@@ -1025,7 +1083,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
markUsed(n.info, f)
|
||||
styleCheckUse(n.info, f)
|
||||
result = newNodeIT(nkDotExpr, n.info, f.typ)
|
||||
result.add makeDeref(newSymNode(c.p.selfSym))
|
||||
result.add makeDeref(newSymNode(p.selfSym))
|
||||
result.add newSymNode(f) # we now have the correct field
|
||||
if check != nil:
|
||||
check.sons[0] = result
|
||||
@@ -1051,7 +1109,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# here at all!
|
||||
#if isSymChoice(n.sons[1]): return
|
||||
|
||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
|
||||
if s != nil:
|
||||
if s.kind in OverloadableSyms:
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
@@ -1186,7 +1244,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result.add(x[0])
|
||||
return
|
||||
checkMinSonsLen(n, 2)
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck})
|
||||
# make sure we don't evaluate generic macros/templates
|
||||
n.sons[0] = semExprWithType(c, n.sons[0],
|
||||
{efNoProcvarCheck, efNoEvaluateGeneric})
|
||||
let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
case arr.kind
|
||||
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
|
||||
@@ -1229,12 +1289,30 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
let s = if n.sons[0].kind == nkSym: n.sons[0].sym
|
||||
elif n[0].kind in nkSymChoices: n.sons[0][0].sym
|
||||
else: nil
|
||||
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
# type parameters: partial generic specialization
|
||||
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
|
||||
result = explicitGenericInstantiation(c, n, s)
|
||||
elif s != nil and s.kind == skType:
|
||||
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
|
||||
if s != nil:
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skIterator:
|
||||
# type parameters: partial generic specialization
|
||||
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
|
||||
result = explicitGenericInstantiation(c, n, s)
|
||||
of skMacro, skTemplate:
|
||||
if efInCall in flags:
|
||||
# We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
|
||||
# Return as is, so it can be transformed into complete macro or
|
||||
# template call in semIndirectOp caller.
|
||||
result = n
|
||||
else:
|
||||
# We are processing macroOrTmpl[] not in call. Transform it to the
|
||||
# macro or template call with generic arguments here.
|
||||
n.kind = nkCall
|
||||
case s.kind
|
||||
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||
else: discard
|
||||
of skType:
|
||||
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
|
||||
else:
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
else:
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
|
||||
@@ -1287,7 +1365,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||
n.sons[1] = takeImplicitAddr(c, ri)
|
||||
x.typ.flags.incl tfVarIsPtr
|
||||
|
||||
template resultTypeIsInferrable(typ: PType): expr =
|
||||
template resultTypeIsInferrable(typ: PType): untyped =
|
||||
typ.isMetaType and typ.kind != tyTypeDesc
|
||||
|
||||
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
@@ -1313,15 +1391,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
# --> `[]=`(a, i, x)
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
a = semSubscript(c, a, {efLValue})
|
||||
if a == nil and mode != noOverloadedSubscript:
|
||||
if a == nil:
|
||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
||||
add(result, n[1])
|
||||
result = semExprNoType(c, result)
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
return result
|
||||
elif a == nil:
|
||||
localError(n.info, "could not resolve: " & $n[0])
|
||||
return n
|
||||
if mode == noOverloadedSubscript:
|
||||
bracketNotFoundError(c, result)
|
||||
return n
|
||||
else:
|
||||
result = semExprNoType(c, result)
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
return result
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
of nkCurlyExpr:
|
||||
# a{i} = x --> `{}=`(a, i, x)
|
||||
@@ -1557,8 +1636,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
||||
result.flags = {sfGenSym}
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
var macroCall = n[1]
|
||||
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
||||
let macroCall = n[1]
|
||||
let expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
||||
if expandedSym.kind == skError: return n
|
||||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
@@ -1566,11 +1645,12 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
styleCheckUse(n.info, expandedSym)
|
||||
|
||||
for i in countup(1, macroCall.len-1):
|
||||
#if macroCall.sons[0].typ.sons[i].kind != tyExpr:
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
internalAssert n.sons[0].sym.magic == mExpandToAst
|
||||
#n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
|
||||
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
|
||||
n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
|
||||
else: sysTypeFromName"PNimrodNode"
|
||||
result = n
|
||||
@@ -1810,8 +1890,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
# the correct branch. Otherwise the AST will be passed through semStmt.
|
||||
result = nil
|
||||
|
||||
template setResult(e: expr) =
|
||||
if semCheck: result = semStmt(c, e) # do not open a new scope!
|
||||
template setResult(e: untyped) =
|
||||
if semCheck: result = semExpr(c, e) # do not open a new scope!
|
||||
else: result = e
|
||||
|
||||
# Check if the node is "when nimvm"
|
||||
@@ -1820,6 +1900,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
# else:
|
||||
# ...
|
||||
var whenNimvm = false
|
||||
var typ = commonTypeBegin
|
||||
if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
|
||||
n.sons[1].kind == nkElse:
|
||||
let exprNode = n.sons[0].sons[0]
|
||||
@@ -1836,7 +1917,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
checkSonsLen(it, 2)
|
||||
if whenNimvm:
|
||||
if semCheck:
|
||||
it.sons[1] = semStmt(c, it.sons[1])
|
||||
it.sons[1] = semExpr(c, it.sons[1])
|
||||
typ = commonType(typ, it.sons[1].typ)
|
||||
result = n # when nimvm is not elimited until codegen
|
||||
else:
|
||||
var e = semConstExpr(c, it.sons[0])
|
||||
@@ -1850,12 +1932,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
checkSonsLen(it, 1)
|
||||
if result == nil or whenNimvm:
|
||||
if semCheck:
|
||||
it.sons[0] = semStmt(c, it.sons[0])
|
||||
it.sons[0] = semExpr(c, it.sons[0])
|
||||
typ = commonType(typ, it.sons[0].typ)
|
||||
if result == nil:
|
||||
result = it.sons[0]
|
||||
else: illFormedAst(n)
|
||||
if result == nil:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
if whenNimvm: result.typ = typ
|
||||
# The ``when`` statement implements the mechanism for platform dependent
|
||||
# code. Thus we try to ensure here consistent ID allocation after the
|
||||
# ``when`` statement.
|
||||
@@ -2132,7 +2216,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if nfSem in n.flags: return
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
var s = lookUp(c, n)
|
||||
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
|
||||
else: {checkUndeclared, checkModule, checkAmbiguity}
|
||||
var s = qualifiedLookUp(c, n, checks)
|
||||
if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
|
||||
result = semSym(c, n, s, flags)
|
||||
if s.kind in {skProc, skMethod, skConverter, skIterator}:
|
||||
@@ -2220,7 +2306,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
elif n.len == 1:
|
||||
result = semObjConstr(c, n, flags)
|
||||
elif contains(c.ambiguousSymbols, s.id):
|
||||
localError(n.info, errUseQualifier, s.name.s)
|
||||
errorUseQualifier(c, n.info, s)
|
||||
elif s.magic == mNone: result = semDirectOp(c, n, flags)
|
||||
else: result = semMagic(c, n, s, flags)
|
||||
of skProc, skMethod, skConverter, skIterator:
|
||||
@@ -2336,7 +2422,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
|
||||
result = evalFrom(c, n)
|
||||
of nkIncludeStmt:
|
||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
|
||||
#if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
|
||||
result = evalInclude(c, n)
|
||||
of nkExportStmt, nkExportExceptStmt:
|
||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
|
||||
|
||||
@@ -143,7 +143,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
const ordIntLit = {nkIntLit..nkUInt64Lit}
|
||||
result = n.typ
|
||||
|
||||
template commutativeOp(opr: expr) {.immediate.} =
|
||||
template commutativeOp(opr: untyped) =
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ):
|
||||
@@ -151,7 +151,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
opr(pickMinInt(a), pickMinInt(b)),
|
||||
opr(pickMaxInt(a), pickMaxInt(b)))
|
||||
|
||||
template binaryOp(opr: expr) {.immediate.} =
|
||||
template binaryOp(opr: untyped) =
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
@@ -286,13 +286,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
|
||||
of mBitnotI: result = newIntNodeT(not getInt(a), n)
|
||||
of mLengthStr, mXLenStr:
|
||||
if a.kind == nkNilLit: result = newIntNodeT(0, n)
|
||||
else: result = newIntNodeT(len(getStr(a)), n)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
|
||||
of mLengthSeq, mLengthOpenArray, mXLenSeq:
|
||||
if a.kind == nkNilLit: result = newIntNodeT(0, n)
|
||||
else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
|
||||
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
|
||||
if a.kind == nkNilLit:
|
||||
result = newIntNodeT(0, n)
|
||||
elif a.kind in {nkStrLit..nkTripleStrLit}:
|
||||
result = newIntNodeT(len a.strVal, n)
|
||||
else:
|
||||
result = newIntNodeT(sonsLen(a), n) # BUGFIX
|
||||
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
||||
of mToFloat, mToBiggestFloat:
|
||||
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
||||
@@ -419,7 +420,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
|
||||
int(getOrdValue(c))), n)
|
||||
of mFloatToStr: result = newStrNodeT($getFloat(a), n)
|
||||
of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
|
||||
of mCStrToStr, mCharToStr:
|
||||
if a.kind == nkBracket:
|
||||
var s = ""
|
||||
for b in a.sons:
|
||||
s.add b.getStrOrChar
|
||||
result = newStrNodeT(s, n)
|
||||
else:
|
||||
result = newStrNodeT(getStrOrChar(a), n)
|
||||
of mStrToStr: result = a
|
||||
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
|
||||
of mArrToSeq:
|
||||
@@ -482,7 +490,7 @@ proc leValueConv(a, b: PNode): bool =
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case b.kind
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
|
||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
|
||||
else: internalError(a.info, "leValueConv")
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
case b.kind
|
||||
@@ -627,14 +635,20 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
||||
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
|
||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
||||
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
|
||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
|
||||
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
|
||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
|
||||
of mAppType: result = getAppType(n)
|
||||
of mNaN: result = newFloatNodeT(NaN, n)
|
||||
of mInf: result = newFloatNodeT(Inf, n)
|
||||
of mNegInf: result = newFloatNodeT(NegInf, n)
|
||||
of mIntDefine:
|
||||
if isDefined(s.name):
|
||||
result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
|
||||
of mStrDefine:
|
||||
if isDefined(s.name):
|
||||
result = newStrNodeT(lookupSymbol(s.name), n)
|
||||
else:
|
||||
if sfFakeConst notin s.flags: result = copyTree(s.ast)
|
||||
result = copyTree(s.ast)
|
||||
of {skProc, skMethod}:
|
||||
result = n
|
||||
of skType:
|
||||
|
||||
@@ -47,8 +47,11 @@ proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
result = semGenericStmt(c, n, flags, ctx)
|
||||
closeScope(c)
|
||||
|
||||
template macroToExpand(s: expr): expr =
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
||||
template macroToExpand(s): untyped =
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
|
||||
|
||||
template macroToExpandSym(s): untyped =
|
||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1)
|
||||
|
||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
ctx: var GenericCtx): PNode =
|
||||
@@ -61,14 +64,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
of skProc, skMethod, skIterator, skConverter, skModule:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
if macroToExpandSym(s):
|
||||
styleCheckUse(n.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
if macroToExpandSym(s):
|
||||
styleCheckUse(n.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
@@ -124,7 +127,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
assert n.kind == nkDotExpr
|
||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||
|
||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
|
||||
|
||||
var s = qualifiedLookUp(c, n, luf)
|
||||
if s != nil:
|
||||
@@ -199,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
if s != nil:
|
||||
incl(s.flags, sfUsed)
|
||||
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
||||
let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
|
||||
let sc = symChoice(c, fn, s,
|
||||
if s.name.id in ctx.toMixin: scForceOpen else: scOpen)
|
||||
case s.kind
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
if macroToExpand(s) and sc.safeLen <= 1:
|
||||
styleCheckUse(fn.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||
n.sons[0] = sc
|
||||
result = n
|
||||
mixinContext = true
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
if macroToExpand(s) and sc.safeLen <= 1:
|
||||
styleCheckUse(fn.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||
n.sons[0] = sc
|
||||
result = n
|
||||
# BUGFIX: we must not return here, we need to do first phase of
|
||||
# symbol lookup. Also since templates and macros can do scope injections
|
||||
@@ -227,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
# Leave it as an identifier.
|
||||
discard
|
||||
of skProc, skMethod, skIterator, skConverter, skModule:
|
||||
result.sons[0] = symChoice(c, fn, s, scOption)
|
||||
result.sons[0] = sc
|
||||
# do not check of 's.magic==mRoof' here because it might be some
|
||||
# other '^' but after overload resolution the proper one:
|
||||
if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
|
||||
@@ -426,7 +430,12 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
|
||||
var body: PNode
|
||||
if n.sons[namePos].kind == nkSym: body = n.sons[namePos].sym.getBody
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
let s = n.sons[namePos].sym
|
||||
if sfGenSym in s.flags and s.ast == nil:
|
||||
body = n.sons[bodyPos]
|
||||
else:
|
||||
body = s.getBody
|
||||
else: body = n.sons[bodyPos]
|
||||
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
|
||||
closeScope(c)
|
||||
|
||||
@@ -43,9 +43,11 @@ proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||
if arg.name.id == c.selfName.id:
|
||||
c.p.selfSym = arg
|
||||
arg.flags.incl sfIsSelf
|
||||
let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
|
||||
if t.kind == tyObject:
|
||||
var t = c.p.selfSym.typ.skipTypes(abstractPtrs)
|
||||
while t.kind == tyObject:
|
||||
addObjFieldsToLocalScope(c, t.n)
|
||||
if t.sons[0] == nil: break
|
||||
t = t.sons[0].skipTypes(abstractPtrs)
|
||||
|
||||
proc pushProcCon*(c: PContext; owner: PSym) =
|
||||
rawPushProcCon(c, owner)
|
||||
@@ -111,9 +113,9 @@ proc removeDefaultParamValues(n: PNode) =
|
||||
# not possible... XXX We don't solve this issue here.
|
||||
a.sons[L-1] = ast.emptyNode
|
||||
|
||||
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
||||
# we need to create a fresh set of gensym'ed symbols:
|
||||
if n.kind == nkSym and sfGenSym in n.sym.flags:
|
||||
if n.kind == nkSym and sfGenSym in n.sym.flags and n.sym.owner == orig:
|
||||
let s = n.sym
|
||||
var x = PSym(idTableGet(symMap, s))
|
||||
if x == nil:
|
||||
@@ -122,7 +124,7 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||
idTablePut(symMap, s, x)
|
||||
n.sym = x
|
||||
else:
|
||||
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
|
||||
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap)
|
||||
|
||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||
|
||||
@@ -137,7 +139,7 @@ proc addProcDecls(c: PContext, fn: PSym) =
|
||||
|
||||
maybeAddResult(c, fn, fn.ast)
|
||||
|
||||
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
||||
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
inc c.inGenericInst
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
@@ -149,7 +151,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
||||
let param = params[i].sym
|
||||
if sfGenSym in param.flags:
|
||||
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
|
||||
freshGenSyms(b, result, symMap)
|
||||
freshGenSyms(b, result, orig, symMap)
|
||||
b = semProcBody(c, b)
|
||||
b = hloBody(c, b)
|
||||
n.sons[bodyPos] = transformBody(c.module, b, result)
|
||||
@@ -165,7 +167,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
openScope(c)
|
||||
var n = oldPrc.ast
|
||||
n.sons[bodyPos] = copyTree(s.getBody)
|
||||
instantiateBody(c, n, nil, oldPrc)
|
||||
instantiateBody(c, n, nil, oldPrc, s)
|
||||
closeScope(c)
|
||||
popInfoContext()
|
||||
|
||||
@@ -203,7 +205,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
# The solution would be to move this logic into semtypinst, but
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc.
|
||||
addDecl(c, prc)
|
||||
#addDecl(c, prc)
|
||||
|
||||
pushInfoContext(info)
|
||||
var cl = initTypeVars(c, pt, info, nil)
|
||||
@@ -312,7 +314,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
if isNil(n.sons[bodyPos]):
|
||||
n.sons[bodyPos] = copyTree(fn.getBody)
|
||||
instantiateBody(c, n, fn.typ.n, result)
|
||||
instantiateBody(c, n, fn.typ.n, result, fn)
|
||||
sideEffectsCheck(c, result)
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
|
||||
@@ -12,25 +12,26 @@
|
||||
|
||||
import ast, astalgo, msgs, types
|
||||
|
||||
proc ithField(n: PNode, field: int): PSym =
|
||||
proc ithField(n: PNode, field: var int): PSym =
|
||||
result = nil
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = ithField(n.sons[i], field-i)
|
||||
result = ithField(n.sons[i], field)
|
||||
if result != nil: return
|
||||
of nkRecCase:
|
||||
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
|
||||
result = ithField(n.sons[0], field-1)
|
||||
result = ithField(n.sons[0], field)
|
||||
if result != nil: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
result = ithField(lastSon(n.sons[i]), field-1)
|
||||
result = ithField(lastSon(n.sons[i]), field)
|
||||
if result != nil: return
|
||||
else: internalError(n.info, "ithField(record case branch)")
|
||||
of nkSym:
|
||||
if field == 0: result = n.sym
|
||||
else: dec(field)
|
||||
else: discard
|
||||
|
||||
proc annotateType*(n: PNode, t: PType) =
|
||||
@@ -39,10 +40,13 @@ proc annotateType*(n: PNode, t: PType) =
|
||||
# to not to skip tyGenericInst
|
||||
case n.kind
|
||||
of nkObjConstr:
|
||||
let x = t.skipTypes(abstractPtrs)
|
||||
n.typ = t
|
||||
for i in 1 .. <n.len:
|
||||
let field = x.n.ithField(i - 1)
|
||||
if field.isNil: globalError n.info, "invalid field at index " & $i
|
||||
var j = i-1
|
||||
let field = x.n.ithField(j)
|
||||
if field.isNil:
|
||||
globalError n.info, "invalid field at index " & $i
|
||||
else:
|
||||
internalAssert(n.sons[i].kind == nkExprColonExpr)
|
||||
annotateType(n.sons[i].sons[1], field.typ)
|
||||
|
||||
@@ -42,7 +42,10 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
result = semSubscript(c, result, flags)
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
if result.isNil:
|
||||
localError(n.info, "could not resolve: " & $n)
|
||||
let x = copyTree(n)
|
||||
x.sons[0] = newIdentNode(getIdent"[]", n.info)
|
||||
bracketNotFoundError(c, x)
|
||||
#localError(n.info, "could not resolve: " & $n)
|
||||
result = n
|
||||
|
||||
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
@@ -111,8 +114,12 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semOrd(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
result.typ = makeRangeType(c, firstOrd(n.sons[1].typ),
|
||||
lastOrd(n.sons[1].typ), n.info)
|
||||
let parType = n.sons[1].typ
|
||||
if isOrdinalType(parType) or parType.kind == tySet:
|
||||
result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info)
|
||||
else:
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
result.typ = errorType(c)
|
||||
|
||||
proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
result = copyNode(n)
|
||||
@@ -130,7 +137,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||
return errorNode(c, n)
|
||||
|
||||
let id = newIdentNode(getIdent(sl.strVal), n.info)
|
||||
let s = qualifiedLookUp(c, id)
|
||||
let s = qualifiedLookUp(c, id, {checkUndeclared})
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
||||
@@ -203,7 +210,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = n.sons[1]
|
||||
else:
|
||||
result = newNodeIT(nkCall, n.info, getSysType(tyInt))
|
||||
result.add newSymNode(getSysMagic("-", mSubI), n.info)
|
||||
let subi = getSysMagic("-", mSubI)
|
||||
#echo "got ", typeToString(subi.typ)
|
||||
result.add newSymNode(subi, n.info)
|
||||
result.add lenExprB
|
||||
result.add n.sons[1]
|
||||
of mPlugin:
|
||||
|
||||
@@ -74,8 +74,6 @@ type
|
||||
currentSpawnId: int
|
||||
inLoop: int
|
||||
|
||||
let opSlice = createMagic("slice", mSlice)
|
||||
|
||||
proc initAnalysisCtx(): AnalysisCtx =
|
||||
result.locals = @[]
|
||||
result.slices = @[]
|
||||
@@ -123,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
|
||||
else:
|
||||
for i in 0 .. <n.safeLen: checkLocal(c, n.sons[i])
|
||||
|
||||
template `?`(x): expr = x.renderTree
|
||||
template `?`(x): untyped = x.renderTree
|
||||
|
||||
proc checkLe(c: AnalysisCtx; a, b: PNode) =
|
||||
case proveLe(c.guards, a, b)
|
||||
@@ -262,7 +260,7 @@ proc min(a, b: PNode): PNode =
|
||||
|
||||
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
||||
|
||||
template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
|
||||
template pushSpawnId(c, body) {.dirty.} =
|
||||
inc c.spawns
|
||||
let oldSpawnId = c.currentSpawnId
|
||||
c.currentSpawnId = c.spawns
|
||||
@@ -399,7 +397,9 @@ proc transformSlices(n: PNode): PNode =
|
||||
let op = n[0].sym
|
||||
if op.name.s == "[]" and op.fromSystem:
|
||||
result = copyNode(n)
|
||||
result.add opSlice.newSymNode
|
||||
let opSlice = newSymNode(createMagic("slice", mSlice))
|
||||
opSlice.typ = getSysType(tyInt)
|
||||
result.add opSlice
|
||||
result.add n[1]
|
||||
let slice = n[2].skipStmtList
|
||||
result.add slice[1]
|
||||
|
||||
@@ -151,7 +151,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||
guardGlobal(a, n, g)
|
||||
|
||||
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
|
||||
template compileToCpp(a): expr =
|
||||
template compileToCpp(a): untyped =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
|
||||
if a.inTryStmt > 0 and not compileToCpp(a):
|
||||
incl(s.flags, sfVolatile)
|
||||
@@ -459,7 +459,7 @@ proc documentRaises*(n: PNode) =
|
||||
if p4 != nil: n.sons[pragmasPos].add p4
|
||||
if p5 != nil: n.sons[pragmasPos].add p5
|
||||
|
||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||
template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||
|
||||
proc importedFromC(n: PNode): bool =
|
||||
# when imported from C, we assume GC-safety.
|
||||
@@ -505,7 +505,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
# addr(x[]) can't be proven, but addr(x) can:
|
||||
if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
|
||||
elif (n.kind == nkSym and n.sym.kind in routineKinds) or
|
||||
n.kind in procDefs+{nkObjConstr}:
|
||||
n.kind in procDefs+{nkObjConstr, nkBracket}:
|
||||
# 'p' is not nil obviously:
|
||||
return
|
||||
case impliesNotNil(tracked.guards, n)
|
||||
@@ -532,7 +532,7 @@ proc isOwnedProcVar(n: PNode; owner: PSym): bool =
|
||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let a = skipConvAndClosure(n)
|
||||
let op = a.typ
|
||||
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
|
||||
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
|
||||
internalAssert op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
let s = n.skipConv
|
||||
|
||||
@@ -17,7 +17,8 @@ proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
checkSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
||||
if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone:
|
||||
localError(n.info, errInvalidDiscard)
|
||||
|
||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -137,7 +138,7 @@ proc fixNilType(n: PNode) =
|
||||
|
||||
proc discardCheck(c: PContext, result: PNode) =
|
||||
if c.inTypeClass > 0: return
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||
if result.kind == nkNilLit:
|
||||
result.typ = nil
|
||||
message(result.info, warnNilStatement)
|
||||
@@ -303,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||
result = fitNode(c, typ, n)
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
changeType(result.sons[1], typ, check=true)
|
||||
result = result.sons[1]
|
||||
let r1 = result.sons[1]
|
||||
if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
|
||||
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
|
||||
result.info = n.info
|
||||
result.typ = typ
|
||||
else:
|
||||
changeType(r1, typ, check=true)
|
||||
result = r1
|
||||
elif not sameType(result.typ, typ):
|
||||
changeType(result, typ, check=false)
|
||||
|
||||
@@ -336,7 +343,7 @@ proc checkNilable(v: PSym) =
|
||||
{tfNotNil, tfNeedsInit} * v.typ.flags != {}:
|
||||
if v.ast.isNil:
|
||||
message(v.info, warnProveInit, v.name.s)
|
||||
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||
elif tfNeedsInit in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||
message(v.info, warnProveInit, v.name.s)
|
||||
|
||||
include semasgn
|
||||
@@ -410,6 +417,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
|
||||
if a.sons[length-1].kind != nkEmpty:
|
||||
localError(a.info, "'using' sections cannot contain assignments")
|
||||
|
||||
proc hasEmpty(typ: PType): bool =
|
||||
if typ.kind in {tySequence, tyArray, tySet}:
|
||||
result = typ.lastSon.kind == tyEmpty
|
||||
elif typ.kind == tyTuple:
|
||||
for s in typ.sons:
|
||||
result = result or hasEmpty(s)
|
||||
|
||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
var b: PNode
|
||||
result = copyNode(n)
|
||||
@@ -444,10 +458,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
#changeType(def.skipConv, typ, check=true)
|
||||
else:
|
||||
typ = skipIntLit(def.typ)
|
||||
if typ.kind in {tySequence, tyArray, tySet} and
|
||||
typ.lastSon.kind == tyEmpty:
|
||||
if hasEmpty(typ):
|
||||
localError(def.info, errCannotInferTypeOfTheLiteral,
|
||||
($typ.kind).substr(2).toLower)
|
||||
($typ.kind).substr(2).toLowerAscii)
|
||||
else:
|
||||
def = ast.emptyNode
|
||||
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
||||
@@ -535,7 +548,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
localError(a.sons[2].info, errConstExprExpected)
|
||||
continue
|
||||
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
|
||||
localError(a.info, errXisNoType, typeToString(typ))
|
||||
localError(a.info, "invalid type for const: " & typeToString(typ))
|
||||
continue
|
||||
v.typ = typ
|
||||
v.ast = def # no need to copy
|
||||
@@ -668,7 +681,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||
let name = a.sons[0]
|
||||
var s: PSym
|
||||
if name.kind == nkDotExpr:
|
||||
s = qualifiedLookUp(c, name)
|
||||
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
||||
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
||||
localError(name.info, "only .partial objects can be extended")
|
||||
else:
|
||||
@@ -710,7 +723,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||
a.sons[1] = s.typ.n
|
||||
s.typ.size = -1 # could not be computed properly
|
||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||
# so we use tyNone instead of nil to not crash for strange conversions
|
||||
# like: mydata.seq
|
||||
rawAddSon(s.typ, newTypeS(tyNone, c))
|
||||
s.ast = a
|
||||
@@ -778,11 +791,16 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
var s = a.sons[0].sym
|
||||
# compute the type's size and check for illegal recursions:
|
||||
if a.sons[1].kind == nkEmpty:
|
||||
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
|
||||
var x = a[2]
|
||||
while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
|
||||
x = x.lastSon
|
||||
if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
|
||||
s.typ.kind notin {tyObject, tyEnum}:
|
||||
# type aliases are hard:
|
||||
#MessageOut('for type ' + typeToString(s.typ));
|
||||
var t = semTypeNode(c, a.sons[2], nil)
|
||||
if t.kind in {tyObject, tyEnum}:
|
||||
var t = semTypeNode(c, x, nil)
|
||||
assert t != nil
|
||||
if t.kind in {tyObject, tyEnum, tyDistinct}:
|
||||
assert s.typ != nil
|
||||
assignType(s.typ, t)
|
||||
s.typ.id = t.id # same id
|
||||
checkConstructedType(s.info, s.typ)
|
||||
@@ -924,6 +942,17 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||
return
|
||||
|
||||
proc setGenericParamsMisc(c: PContext; n: PNode): PNode =
|
||||
let orig = n.sons[genericParamsPos]
|
||||
# we keep the original params around for better error messages, see
|
||||
# issue https://github.com/nim-lang/Nim/issues/1713
|
||||
result = semGenericParamList(c, orig)
|
||||
if n.sons[miscPos].kind == nkEmpty:
|
||||
n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig)
|
||||
else:
|
||||
n.sons[miscPos].sons[1] = orig
|
||||
n.sons[genericParamsPos] = result
|
||||
|
||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# XXX semProcAux should be good enough for this now, we will eventually
|
||||
# remove semLambda
|
||||
@@ -942,8 +971,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
openScope(c)
|
||||
var gp: PNode
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||
gp = n.sons[genericParamsPos]
|
||||
gp = setGenericParamsMisc(c, n)
|
||||
else:
|
||||
gp = newNodeI(nkGenericParams, n.info)
|
||||
|
||||
@@ -1165,8 +1193,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
openScope(c)
|
||||
var gp: PNode
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||
gp = n.sons[genericParamsPos]
|
||||
gp = setGenericParamsMisc(c, n)
|
||||
else:
|
||||
gp = newNodeI(nkGenericParams, n.info)
|
||||
# process parameters:
|
||||
@@ -1231,6 +1258,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
pushOwner(s)
|
||||
s.options = gOptions
|
||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||
if s.name.s[0] in {'.', '('}:
|
||||
if s.name.s in [".", ".()", ".=", "()"] and not experimentalMode(c):
|
||||
message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s)
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
# for DLL generation it is annoying to check for sfImportc!
|
||||
if sfBorrow in s.flags:
|
||||
@@ -1245,7 +1275,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
|
||||
c.p.wasForwarded = proto != nil
|
||||
maybeAddResult(c, s, n)
|
||||
if sfImportc notin s.flags:
|
||||
if lfDynamicLib notin s.loc.flags:
|
||||
# no semantic checking for importc:
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||
@@ -1285,6 +1315,7 @@ proc determineType(c: PContext, s: PSym) =
|
||||
|
||||
proc semIterator(c: PContext, n: PNode): PNode =
|
||||
# gensym'ed iterator?
|
||||
let isAnon = n[namePos].kind == nkEmpty
|
||||
if n[namePos].kind == nkSym:
|
||||
# gensym'ed iterators might need to become closure iterators:
|
||||
n[namePos].sym.owner = getCurrOwner()
|
||||
@@ -1294,6 +1325,8 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||
var t = s.typ
|
||||
if t.sons[0] == nil and s.typ.callConv != ccClosure:
|
||||
localError(n.info, errXNeedsReturnType, "iterator")
|
||||
if isAnon and s.typ.callConv == ccInline:
|
||||
localError(n.info, "inline iterators are not first-class / cannot be assigned to variables")
|
||||
# iterators are either 'inline' or 'closure'; for backwards compatibility,
|
||||
# we require first class iterators to be marked with 'closure' explicitly
|
||||
# -- at least for 0.9.2.
|
||||
@@ -1325,9 +1358,24 @@ proc finishMethod(c: PContext, s: PSym) =
|
||||
proc semMethod(c: PContext, n: PNode): PNode =
|
||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||
|
||||
# macros can transform methods to nothing:
|
||||
if namePos >= result.safeLen: return result
|
||||
var s = result.sons[namePos].sym
|
||||
if not isGenericRoutine(s):
|
||||
if isGenericRoutine(s):
|
||||
let tt = s.typ
|
||||
var foundObj = false
|
||||
# we start at 1 for now so that tparsecombnum continues to compile.
|
||||
# XXX Revisit this problem later.
|
||||
for col in countup(1, sonsLen(tt)-1):
|
||||
let t = tt.sons[col]
|
||||
if t != nil and t.kind == tyGenericInvocation:
|
||||
var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody})
|
||||
if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len:
|
||||
foundObj = true
|
||||
x.methods.safeAdd((col,s))
|
||||
if not foundObj:
|
||||
message(n.info, warnDeprecated, "generic method not attachable to object type")
|
||||
else:
|
||||
# why check for the body? bug #2400 has none. Checking for sfForward makes
|
||||
# no sense either.
|
||||
# and result.sons[bodyPos].kind != nkEmpty:
|
||||
@@ -1340,6 +1388,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||
# macros can transform converters to nothing:
|
||||
if namePos >= result.safeLen: return result
|
||||
var s = result.sons[namePos].sym
|
||||
var t = s.typ
|
||||
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
|
||||
@@ -1349,6 +1399,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
result = semProcAux(c, n, skMacro, macroPragmas)
|
||||
# macros can transform macros to nothing:
|
||||
if namePos >= result.safeLen: return result
|
||||
var s = result.sons[namePos].sym
|
||||
var t = s.typ
|
||||
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
||||
|
||||
@@ -51,9 +51,10 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||
var i = 0
|
||||
a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind != skModule:
|
||||
inc(i)
|
||||
if i > 1: break
|
||||
a = nextOverloadIter(o, c, n)
|
||||
inc(i)
|
||||
if i > 1: break
|
||||
if i <= 1 and r != scForceOpen:
|
||||
# XXX this makes more sense but breaks bootstrapping for now:
|
||||
# (s.kind notin routineKinds or s.magic != mNone):
|
||||
@@ -68,8 +69,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
|
||||
a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
incl(a.flags, sfUsed)
|
||||
addSon(result, newSymNode(a, n.info))
|
||||
if a.kind != skModule:
|
||||
incl(a.flags, sfUsed)
|
||||
addSon(result, newSymNode(a, n.info))
|
||||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
@@ -80,7 +82,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
# the same symbol!
|
||||
# This is however not true anymore for hygienic templates as semantic
|
||||
# processing for them changes the symbol table...
|
||||
let s = qualifiedLookUp(c, a)
|
||||
let s = qualifiedLookUp(c, a, {checkUndeclared})
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
let sc = symChoice(c, n, s, scClosed)
|
||||
@@ -577,13 +579,16 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
gp = newNodeI(nkGenericParams, n.info)
|
||||
# process parameters:
|
||||
var allUntyped = true
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
semParamList(c, n.sons[paramsPos], gp, s)
|
||||
# a template's parameters are not gensym'ed even if that was originally the
|
||||
# case as we determine whether it's a template parameter in the template
|
||||
# body by the absence of the sfGenSym flag:
|
||||
for i in 1 .. s.typ.n.len-1:
|
||||
s.typ.n.sons[i].sym.flags.excl sfGenSym
|
||||
let param = s.typ.n.sons[i].sym
|
||||
param.flags.excl sfGenSym
|
||||
if param.typ.kind != tyExpr: allUntyped = false
|
||||
if sonsLen(gp) > 0:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
# we have a list of implicit type parameters:
|
||||
@@ -599,6 +604,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
s.typ.n = newNodeI(nkFormalParams, n.info)
|
||||
rawAddSon(s.typ, newTypeS(tyStmt, c))
|
||||
addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
|
||||
if allUntyped: incl(s.flags, sfAllUntyped)
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||
var ctx: TemplCtx
|
||||
@@ -628,8 +634,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
c.patterns.add(s)
|
||||
|
||||
proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||
template templToExpand(s: expr): expr =
|
||||
s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags)
|
||||
template templToExpand(s: untyped): untyped =
|
||||
s.kind == skTemplate and (s.typ.len == 1 or sfAllUntyped in s.flags)
|
||||
|
||||
proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
|
||||
# the param added in the current scope is actually wrong here for
|
||||
|
||||
@@ -130,7 +130,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
if n.len < 1:
|
||||
result = newConstraint(c, kind)
|
||||
else:
|
||||
let isCall = ord(n.kind in nkCallKinds)
|
||||
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1)
|
||||
var base = semTypeNode(c, n.lastSon, nil)
|
||||
@@ -370,7 +370,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
@@ -393,20 +393,24 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
addSon(result.n, newSymNode(field))
|
||||
addSonSkipIntLit(result, typ)
|
||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||
if result.n.len == 0: result.n = nil
|
||||
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
# identifier with visibility
|
||||
if n.kind == nkPostfix:
|
||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||
if sonsLen(n) == 2:
|
||||
# for gensym'ed identifiers the identifier may already have been
|
||||
# transformed to a symbol and we need to use that here:
|
||||
result = newSymG(kind, n.sons[1], c)
|
||||
var v = n.sons[0].ident
|
||||
var v = considerQuotedIdent(n.sons[0])
|
||||
if sfExported in allowed and v.id == ord(wStar):
|
||||
incl(result.flags, sfExported)
|
||||
else:
|
||||
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
||||
if not (sfExported in allowed):
|
||||
localError(n.sons[0].info, errXOnlyAtModuleScope, "export")
|
||||
else:
|
||||
localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0]))
|
||||
else:
|
||||
illFormedAst(n)
|
||||
else:
|
||||
@@ -751,18 +755,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
addDecl(c, s)
|
||||
|
||||
# XXX: There are codegen errors if this is turned into a nested proc
|
||||
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||
template liftingWalk(typ: PType, anonFlag = false): untyped =
|
||||
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
||||
#proc liftingWalk(paramType: PType, anon = false): PType =
|
||||
|
||||
var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
|
||||
else: nil
|
||||
|
||||
template maybeLift(typ: PType): expr =
|
||||
template maybeLift(typ: PType): untyped =
|
||||
let lifted = liftingWalk(typ)
|
||||
(if lifted != nil: lifted else: typ)
|
||||
|
||||
template addImplicitGeneric(e: expr): expr =
|
||||
template addImplicitGeneric(e): untyped =
|
||||
addImplicitGenericImpl(e, paramTypId)
|
||||
|
||||
case paramType.kind:
|
||||
@@ -942,7 +946,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
if isType: localError(a.info, "':' expected")
|
||||
if kind in {skTemplate, skMacro}:
|
||||
typ = newTypeS(tyExpr, c)
|
||||
elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty:
|
||||
elif skipTypes(typ, {tyGenericInst}).kind == tyVoid:
|
||||
continue
|
||||
for j in countup(0, length-3):
|
||||
var arg = newSymG(skParam, a.sons[j], c)
|
||||
@@ -974,7 +978,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
if r != nil:
|
||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||
# compiler only checks for 'nil':
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyVoid:
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
if r.kind == tyAnything:
|
||||
# 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
|
||||
@@ -1035,7 +1039,7 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
if s.typ == nil:
|
||||
localError(n.info, "cannot instantiate the '$1' $2" %
|
||||
[s.name.s, ($s.kind).substr(2).toLower])
|
||||
[s.name.s, ($s.kind).substr(2).toLowerAscii])
|
||||
return newOrPrevType(tyError, prev, c)
|
||||
|
||||
var t = s.typ
|
||||
@@ -1094,10 +1098,14 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
result = instGenericContainer(c, n.info, result,
|
||||
allowMetaTypes = false)
|
||||
|
||||
proc semTypeExpr(c: PContext, n: PNode): PType =
|
||||
proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
|
||||
var n = semExprWithType(c, n, {efDetermineType})
|
||||
if n.typ.kind == tyTypeDesc:
|
||||
result = n.typ.base
|
||||
# fix types constructed by macros:
|
||||
if prev != nil and prev.sym != nil and result.sym.isNil:
|
||||
result.sym = prev.sym
|
||||
result.sym.typ = result
|
||||
else:
|
||||
localError(n.info, errTypeExpected, n.renderTree)
|
||||
result = errorType(c)
|
||||
@@ -1177,7 +1185,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
localError(n.info, errGenerated, "invalid type")
|
||||
elif n[0].kind notin nkIdentKinds:
|
||||
result = semTypeExpr(c, n)
|
||||
result = semTypeExpr(c, n, prev)
|
||||
else:
|
||||
let op = considerQuotedIdent(n.sons[0])
|
||||
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
||||
@@ -1218,7 +1226,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
|
||||
result = typExpr.typ
|
||||
else:
|
||||
result = semTypeExpr(c, n)
|
||||
result = semTypeExpr(c, n, prev)
|
||||
of nkWhenStmt:
|
||||
var whenResult = semWhen(c, n, false)
|
||||
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
|
||||
@@ -1241,6 +1249,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = copyType(result, getCurrOwner(), false)
|
||||
for i in countup(1, n.len - 1):
|
||||
result.rawAddSon(semTypeNode(c, n.sons[i], nil))
|
||||
of mDistinct:
|
||||
result = newOrPrevType(tyDistinct, prev, c)
|
||||
addSonSkipIntLit(result, semTypeNode(c, n[1], nil))
|
||||
of mVar:
|
||||
result = newOrPrevType(tyVar, prev, c)
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
if base.kind == tyVar:
|
||||
localError(n.info, errVarVarTypeNotAllowed)
|
||||
base = base.sons[0]
|
||||
addSonSkipIntLit(result, base)
|
||||
of mRef: result = semAnyRef(c, n, tyRef, prev)
|
||||
of mPtr: result = semAnyRef(c, n, tyPtr, prev)
|
||||
of mTuple: result = semTuple(c, n, prev)
|
||||
else: result = semGeneric(c, n, s, prev)
|
||||
of nkDotExpr:
|
||||
var typeExpr = semExpr(c, n)
|
||||
@@ -1370,10 +1391,7 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||
setMagicType(m, tyTypeDesc, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mVoidType:
|
||||
setMagicType(m, tyEmpty, 0)
|
||||
# for historical reasons we conflate 'void' with 'empty' so that '@[]'
|
||||
# has the type 'seq[void]'.
|
||||
m.typ.flags.incl tfVoid
|
||||
setMagicType(m, tyVoid, 0)
|
||||
of mArray:
|
||||
setMagicType(m, tyArray, 0)
|
||||
of mOpenArray:
|
||||
|
||||
@@ -162,7 +162,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
||||
discard
|
||||
of nkSym:
|
||||
result.sym = replaceTypeVarsS(cl, n.sym)
|
||||
if result.sym.typ.kind == tyEmpty:
|
||||
if result.sym.typ.kind == tyVoid:
|
||||
# don't add the 'void' field
|
||||
result = newNode(nkRecList, n.info)
|
||||
of nkRecWhen:
|
||||
@@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# but we already raised an error!
|
||||
rawAddSon(result, header.sons[i])
|
||||
|
||||
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
||||
let bbody = lastSon body
|
||||
var newbody = replaceTypeVarsT(cl, bbody)
|
||||
cl.skipTypedesc = oldSkipTypedesc
|
||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||
@@ -306,25 +307,31 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy)
|
||||
attachedDeepCopy, 1)
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn)
|
||||
attachedAsgn, 1)
|
||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||
for col, meth in items(methods):
|
||||
# we instantiate the known methods belonging to that type, this causes
|
||||
# them to be registered and that's enough, so we 'discard' the result.
|
||||
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
||||
attachedAsgn, col)
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
# don't deal with '(): void':
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyVoid:
|
||||
t.sons[0] = nil
|
||||
|
||||
for i in 1 .. <t.sonsLen:
|
||||
# don't touch any memory unless necessary
|
||||
if t.sons[i].kind == tyEmpty:
|
||||
if t.sons[i].kind == tyVoid:
|
||||
var pos = i
|
||||
for j in i+1 .. <t.sonsLen:
|
||||
if t.sons[j].kind != tyEmpty:
|
||||
if t.sons[j].kind != tyVoid:
|
||||
t.sons[pos] = t.sons[j]
|
||||
t.n.sons[pos] = t.n.sons[j]
|
||||
inc pos
|
||||
@@ -504,6 +511,6 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
popInfoContext()
|
||||
|
||||
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
||||
t: PType): expr =
|
||||
t: PType): untyped =
|
||||
generateTypeInstance(p, pt, arg.info, t)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
CandidateErrors* = seq[PSym]
|
||||
CandidateErrors* = seq[(PSym,int)]
|
||||
TCandidate* = object
|
||||
c*: PContext
|
||||
exactMatches*: int # also misused to prefer iters over procs
|
||||
@@ -49,6 +49,7 @@ type
|
||||
# a distrinct type
|
||||
typedescMatched*: bool
|
||||
isNoCall*: bool # misused for generic type instantiations C[T]
|
||||
mutabilityProblem*: uint8 # tyVar mismatch
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||
# user if overload resolution fails
|
||||
@@ -96,8 +97,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
|
||||
c.calleeSym = nil
|
||||
initIdTable(c.bindings)
|
||||
|
||||
proc put(t: var TIdTable, key, val: PType) {.inline.} =
|
||||
idTablePut(t, key, val.skipIntLit)
|
||||
proc put(c: var TCandidate, key, val: PType) {.inline.} =
|
||||
idTablePut(c.bindings, key, val.skipIntLit)
|
||||
|
||||
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||
binding: PNode, calleeScope = -1) =
|
||||
@@ -129,7 +130,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||
bound = makeTypeDesc(ctx, bound)
|
||||
else:
|
||||
bound = bound.skipTypes({tyTypeDesc})
|
||||
put(c.bindings, formalTypeParam, bound)
|
||||
put(c, formalTypeParam, bound)
|
||||
|
||||
proc newCandidate*(ctx: PContext, callee: PSym,
|
||||
binding: PNode, calleeScope = -1): TCandidate =
|
||||
@@ -220,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
||||
if result != 0: return
|
||||
result = a.convMatches - b.convMatches
|
||||
if result != 0: return
|
||||
result = a.calleeScope - b.calleeScope
|
||||
if result != 0: return
|
||||
# the other way round because of other semantics:
|
||||
result = b.inheritancePenalty - a.inheritancePenalty
|
||||
if result != 0: return
|
||||
# prefer more specialized generic over more general generic:
|
||||
result = complexDisambiguation(a.callee, b.callee)
|
||||
# only as a last resort, consider scoping:
|
||||
if result != 0: return
|
||||
result = a.calleeScope - b.calleeScope
|
||||
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
||||
@@ -242,6 +244,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||
for i in 1 .. <arg.len:
|
||||
result.add(" | ")
|
||||
result.add typeToString(arg[i].typ, prefer)
|
||||
elif arg.typ == nil:
|
||||
result = "void"
|
||||
else:
|
||||
result = arg.typ.typeToString(prefer)
|
||||
|
||||
@@ -253,15 +257,16 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
add(result, renderTree(n.sons[i].sons[0]))
|
||||
add(result, ": ")
|
||||
if arg.typ.isNil:
|
||||
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
|
||||
# XXX we really need to 'tryExpr' here!
|
||||
arg = c.semOperand(c, n.sons[i].sons[1])
|
||||
n.sons[i].typ = arg.typ
|
||||
n.sons[i].sons[1] = arg
|
||||
else:
|
||||
if arg.typ.isNil:
|
||||
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
|
||||
arg = c.semOperand(c, n.sons[i])
|
||||
n.sons[i] = arg
|
||||
if arg.typ.kind == tyError: return
|
||||
if arg.typ != nil and arg.typ.kind == tyError: return
|
||||
add(result, argTypeToString(arg, prefer))
|
||||
if i != sonsLen(n) - 1: add(result, ", ")
|
||||
|
||||
@@ -360,6 +365,50 @@ proc isObjectSubtype(a, f: PType): int =
|
||||
if t != nil:
|
||||
result = depth
|
||||
|
||||
type
|
||||
SkippedPtr = enum skippedNone, skippedRef, skippedPtr
|
||||
|
||||
proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
|
||||
var r = t
|
||||
# we're allowed to skip one level of ptr/ref:
|
||||
var ptrs = 0
|
||||
while r != nil:
|
||||
case r.kind
|
||||
of tyGenericInvocation:
|
||||
r = r.sons[0]
|
||||
of tyRef:
|
||||
inc ptrs
|
||||
skipped = skippedRef
|
||||
r = r.lastSon
|
||||
of tyPtr:
|
||||
inc ptrs
|
||||
skipped = skippedPtr
|
||||
r = r.lastSon
|
||||
of tyGenericBody, tyGenericInst:
|
||||
r = r.lastSon
|
||||
else:
|
||||
break
|
||||
if r.kind == tyObject and ptrs <= 1: result = r
|
||||
|
||||
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
|
||||
var askip = skippedNone
|
||||
var fskip = skippedNone
|
||||
var t = a.skipToObject(askip)
|
||||
let r = f.skipToObject(fskip)
|
||||
if r == nil: return false
|
||||
var depth = 0
|
||||
# XXX sameObjectType can return false here. Need to investigate
|
||||
# why that is but sameObjectType does way too much work here anyway.
|
||||
while t != nil and r.sym != t.sym and askip == fskip:
|
||||
t = t.sons[0]
|
||||
if t != nil: t = t.skipToObject(askip)
|
||||
else: break
|
||||
inc depth
|
||||
if t != nil and askip == fskip:
|
||||
d = depth
|
||||
result = true
|
||||
|
||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||
if a <= b: result = a
|
||||
else: result = b
|
||||
@@ -513,7 +562,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
ff, a: PType): TTypeRelation =
|
||||
var body = ff.skipTypes({tyUserTypeClassInst})
|
||||
if c.inTypeClass > 20:
|
||||
if c.inTypeClass > 4:
|
||||
localError(body.n[3].info, $body.n[3] & " too nested for type matching")
|
||||
return isNone
|
||||
|
||||
@@ -531,7 +580,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
typ = ff.sons[i]
|
||||
param: PSym
|
||||
|
||||
template paramSym(kind): expr =
|
||||
template paramSym(kind): untyped =
|
||||
newSym(kind, typeParamName, body.sym, body.sym.info)
|
||||
|
||||
case typ.kind
|
||||
@@ -598,6 +647,10 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
template subtypeCheck() =
|
||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||
result = isNone
|
||||
|
||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# typeRel can be used to establish various relationships between types:
|
||||
#
|
||||
@@ -619,7 +672,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
assert(f != nil)
|
||||
|
||||
if f.kind == tyExpr:
|
||||
if aOrig != nil: put(c.bindings, f, aOrig)
|
||||
if aOrig != nil: put(c, f, aOrig)
|
||||
return isGeneric
|
||||
|
||||
assert(aOrig != nil)
|
||||
@@ -640,10 +693,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
template bindingRet(res) =
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
if doBind: put(c.bindings, f, bound)
|
||||
put(c, f, bound)
|
||||
return res
|
||||
|
||||
template considerPreviousT(body: stmt) {.immediate.} =
|
||||
template considerPreviousT(body: untyped) =
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
if prev == nil: body
|
||||
else: return typeRel(c, prev, a)
|
||||
@@ -737,6 +790,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
of tyVar:
|
||||
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
||||
else: result = typeRel(c, f.base, aOrig)
|
||||
subtypeCheck()
|
||||
of tyArray, tyArrayConstr:
|
||||
# tyArrayConstr cannot happen really, but
|
||||
# we wanna be safe here
|
||||
@@ -746,7 +800,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if fRange.kind == tyGenericParam:
|
||||
var prev = PType(idTableGet(c.bindings, fRange))
|
||||
if prev == nil:
|
||||
put(c.bindings, fRange, a.sons[0])
|
||||
put(c, fRange, a.sons[0])
|
||||
fRange = a
|
||||
else:
|
||||
fRange = prev
|
||||
@@ -764,7 +818,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# we must correct for the off-by-one discrepancy between
|
||||
# ranges and static params:
|
||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||
put(c.bindings, rangeStaticT, replacementT)
|
||||
put(c, rangeStaticT, replacementT)
|
||||
return isGeneric
|
||||
|
||||
let len = tryResolvingStaticExpr(c, fRange.n[1])
|
||||
@@ -851,6 +905,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if sameDistinctTypes(f, a): result = isEqual
|
||||
elif f.base.kind == tyAnything: result = isGeneric
|
||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
||||
elif a.kind == tyNil and f.base.kind in NilableTypes:
|
||||
result = f.allowsNil
|
||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
||||
of tySet:
|
||||
if a.kind == tySet:
|
||||
@@ -867,6 +923,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
for i in 0..f.len-2:
|
||||
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
||||
result = typeRel(c, f.lastSon, a.lastSon)
|
||||
subtypeCheck()
|
||||
if result <= isConvertible: result = isNone
|
||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||
result = isNilConversion
|
||||
@@ -921,8 +978,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = isConvertible
|
||||
else: discard
|
||||
|
||||
of tyEmpty:
|
||||
if a.kind == tyEmpty: result = isEqual
|
||||
of tyEmpty, tyVoid:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
|
||||
of tyGenericInst:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
@@ -932,21 +989,26 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if a.kind == tyGenericInst and a.sons[0] == f:
|
||||
bindingRet isGeneric
|
||||
let ff = lastSon(f)
|
||||
if ff != nil: result = typeRel(c, ff, a)
|
||||
if ff != nil:
|
||||
result = typeRel(c, ff, a)
|
||||
|
||||
of tyGenericInvocation:
|
||||
var x = a.skipGenericAlias
|
||||
var depth = 0
|
||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||
# simply no match for now:
|
||||
discard
|
||||
elif x.kind == tyGenericInst and
|
||||
(f.sons[0] == x.sons[0]) and
|
||||
((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and
|
||||
(sonsLen(x) - 1 == sonsLen(f)):
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
if x.sons[i].kind == tyGenericParam:
|
||||
internalError("wrong instantiated type!")
|
||||
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
|
||||
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype:
|
||||
# Workaround for regression #4589
|
||||
if f.sons[i].kind != tyTypeDesc: return
|
||||
c.inheritancePenalty += depth
|
||||
result = isGeneric
|
||||
else:
|
||||
let genericBody = f.sons[0]
|
||||
@@ -963,13 +1025,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
#
|
||||
# we steal the generic parameters from the tyGenericBody:
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
var x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
|
||||
let x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
|
||||
if x == nil:
|
||||
discard "maybe fine (for eg. a==tyNil)"
|
||||
elif x.kind in {tyGenericInvocation, tyGenericParam}:
|
||||
internalError("wrong instantiated type!")
|
||||
else:
|
||||
put(c.bindings, f.sons[i], x)
|
||||
put(c, f.sons[i], x)
|
||||
|
||||
of tyAnd:
|
||||
considerPreviousT:
|
||||
@@ -979,6 +1041,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if x < isSubtype: return isNone
|
||||
# 'and' implies minimum matching result:
|
||||
if x < result: result = x
|
||||
if result > isGeneric: result = isGeneric
|
||||
bindingRet result
|
||||
|
||||
of tyOr:
|
||||
@@ -989,6 +1052,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# 'or' implies maximum matching result:
|
||||
if x > result: result = x
|
||||
if result >= isSubtype:
|
||||
if result > isGeneric: result = isGeneric
|
||||
bindingRet result
|
||||
else:
|
||||
result = isNone
|
||||
@@ -1005,7 +1069,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
considerPreviousT:
|
||||
var concrete = concreteType(c, a)
|
||||
if concrete != nil and doBind:
|
||||
put(c.bindings, f, concrete)
|
||||
put(c, f, concrete)
|
||||
return isGeneric
|
||||
|
||||
of tyBuiltInTypeClass:
|
||||
@@ -1013,7 +1077,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
let targetKind = f.sons[0].kind
|
||||
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
|
||||
(targetKind in {tyProc, tyPointer} and a.kind == tyNil):
|
||||
put(c.bindings, f, a)
|
||||
put(c, f, a)
|
||||
return isGeneric
|
||||
else:
|
||||
return isNone
|
||||
@@ -1022,7 +1086,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
considerPreviousT:
|
||||
result = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if result == isGeneric:
|
||||
put(c.bindings, f, a)
|
||||
put(c, f, a)
|
||||
|
||||
of tyCompositeTypeClass:
|
||||
considerPreviousT:
|
||||
@@ -1038,7 +1102,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
else:
|
||||
result = typeRel(c, rootf.lastSon, a)
|
||||
if result != isNone:
|
||||
put(c.bindings, f, a)
|
||||
put(c, f, a)
|
||||
result = isGeneric
|
||||
of tyGenericParam:
|
||||
var x = PType(idTableGet(c.bindings, f))
|
||||
@@ -1072,7 +1136,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if doBind and result notin {isNone, isGeneric}:
|
||||
let concrete = concreteType(c, a)
|
||||
if concrete == nil: return isNone
|
||||
put(c.bindings, f, concrete)
|
||||
put(c, f, concrete)
|
||||
else:
|
||||
result = isGeneric
|
||||
|
||||
@@ -1086,7 +1150,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if concrete == nil:
|
||||
return isNone
|
||||
if doBind:
|
||||
put(c.bindings, f, concrete)
|
||||
put(c, f, concrete)
|
||||
elif result > isGeneric:
|
||||
result = isGeneric
|
||||
elif a.kind == tyEmpty:
|
||||
@@ -1105,7 +1169,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if result != isNone and f.n != nil:
|
||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||
result = isNone
|
||||
if result != isNone: put(c.bindings, f, aOrig)
|
||||
if result != isNone: put(c, f, aOrig)
|
||||
else:
|
||||
result = isNone
|
||||
elif prev.kind == tyStatic:
|
||||
@@ -1133,7 +1197,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = typeRel(c, f.base, a.base)
|
||||
|
||||
if result != isNone:
|
||||
put(c.bindings, f, a)
|
||||
put(c, f, a)
|
||||
else:
|
||||
if tfUnresolved in f.flags:
|
||||
result = typeRel(c, prev.base, a)
|
||||
@@ -1151,7 +1215,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyStmt:
|
||||
if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
|
||||
put(c.bindings, f, aOrig)
|
||||
put(c, f, aOrig)
|
||||
result = isGeneric
|
||||
|
||||
of tyProxy:
|
||||
@@ -1256,6 +1320,13 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
if r == isGeneric:
|
||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||
m.baseTypeMatch = true
|
||||
# bug #4545: allow the call to go through a 'var T':
|
||||
let vt = result.sons[0].typ.sons[1]
|
||||
if vt.kind == tyVar:
|
||||
let x = result.sons[1]
|
||||
let va = newNodeIT(nkHiddenAddr, x.info, vt)
|
||||
va.add x
|
||||
result.sons[1] = va
|
||||
|
||||
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||
case r
|
||||
@@ -1399,7 +1470,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
of isNone:
|
||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||
# do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
|
||||
if a.kind in {tyProxy, tyUnknown}:
|
||||
inc(m.genericMatches)
|
||||
m.fauxMatch = a.kind
|
||||
@@ -1420,6 +1491,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
m.baseTypeMatch = true
|
||||
else:
|
||||
result = userConvMatch(c, m, base(f), a, arg)
|
||||
if result != nil: m.baseTypeMatch = true
|
||||
|
||||
proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||
arg, argOrig: PNode): PNode =
|
||||
@@ -1532,13 +1604,13 @@ proc incrIndexType(t: PType) =
|
||||
assert t.kind == tyArrayConstr
|
||||
inc t.sons[0].n.sons[1].intVal
|
||||
|
||||
template isVarargsUntyped(x): expr =
|
||||
template isVarargsUntyped(x): untyped =
|
||||
x.kind == tyVarargs and x.sons[0].kind == tyExpr and
|
||||
tfOldSchoolExprStmt notin x.sons[0].flags
|
||||
|
||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m: var TCandidate, marker: var IntSet) =
|
||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||
template checkConstraint(n: untyped) {.dirty.} =
|
||||
if not formal.constraint.isNil:
|
||||
if matchNodeKinds(formal.constraint, n):
|
||||
# better match over other routines with no such restriction:
|
||||
@@ -1549,6 +1621,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
if formal.typ.kind == tyVar:
|
||||
if not n.isLValue:
|
||||
m.state = csNoMatch
|
||||
m.mutabilityProblem = uint8(f-1)
|
||||
return
|
||||
|
||||
var
|
||||
@@ -1568,6 +1641,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
|
||||
while a < n.len:
|
||||
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
|
||||
incl(marker, formal.position)
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
@@ -1630,6 +1704,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
# beware of the side-effects in 'prepareOperand'! So only do it for
|
||||
# varargs matching. See tests/metatype/tstatic_overloading.
|
||||
m.baseTypeMatch = false
|
||||
incl(marker, formal.position)
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
@@ -1653,30 +1728,39 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
return
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
#assert(container == nil)
|
||||
|
||||
if formal.typ.isVarargsUntyped:
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
addSon(container, arg)
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
#if f != formalLen - 1: container = nil
|
||||
|
||||
# pick the formal from the end, so that 'x, y, varargs, z' works:
|
||||
f = max(f, formalLen - n.len + a + 1)
|
||||
addSon(container, n.sons[a])
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
inc(f)
|
||||
container = nil
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
#assert(container == nil)
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
addSon(container, arg)
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
#if f != formalLen - 1: container = nil
|
||||
|
||||
# pick the formal from the end, so that 'x, y, varargs, z' works:
|
||||
f = max(f, formalLen - n.len + a + 1)
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
inc(f)
|
||||
container = nil
|
||||
checkConstraint(n.sons[a])
|
||||
inc(a)
|
||||
|
||||
@@ -1707,15 +1791,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||
if formal.ast == nil:
|
||||
if formal.typ.kind == tyVarargs:
|
||||
var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
|
||||
addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
|
||||
container, m, c))
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
else:
|
||||
# no default value
|
||||
m.state = csNoMatch
|
||||
break
|
||||
else:
|
||||
# use default value:
|
||||
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
||||
var def = copyTree(formal.ast)
|
||||
if def.kind == nkNilLit:
|
||||
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
|
||||
setSon(m.call, formal.position + 1, def)
|
||||
inc(f)
|
||||
|
||||
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
@@ -1728,16 +1815,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
result = res != nil
|
||||
|
||||
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
op: TTypeAttachedOp): PSym {.procvar.} =
|
||||
op: TTypeAttachedOp; col: int): PSym {.procvar.} =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, dc.typ)
|
||||
var f = dc.typ.sons[1]
|
||||
if col >= dc.typ.len:
|
||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||
return nil
|
||||
var f = dc.typ.sons[col]
|
||||
if op == attachedDeepCopy:
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
if f.kind == tyVar: f = f.lastSon
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
|
||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||
else:
|
||||
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
||||
assert sfFromGeneric in result.flags
|
||||
@@ -1745,7 +1835,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
include suggest
|
||||
|
||||
when not declared(tests):
|
||||
template tests(s: stmt) {.immediate.} = discard
|
||||
template tests(s: untyped) = discard
|
||||
|
||||
tests:
|
||||
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||
|
||||
@@ -138,7 +138,7 @@ proc suggestField(c: PContext, s: PSym, outputs: var int) =
|
||||
suggestResult(symToSuggest(s, isLocal=true, $ideSug, 100))
|
||||
inc outputs
|
||||
|
||||
template wholeSymTab(cond, section: expr) {.immediate.} =
|
||||
template wholeSymTab(cond, section: untyped) =
|
||||
var isLocal = true
|
||||
for scope in walkScopes(c.currentScope):
|
||||
if scope == c.topLevelScope: isLocal = false
|
||||
@@ -393,6 +393,8 @@ proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} =
|
||||
|
||||
proc markUsed(info: TLineInfo; s: PSym) =
|
||||
incl(s.flags, sfUsed)
|
||||
if s.kind == skEnumField and s.owner != nil:
|
||||
incl(s.owner.flags, sfUsed)
|
||||
if {sfDeprecated, sfError} * s.flags != {}:
|
||||
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
|
||||
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
||||
|
||||
@@ -95,7 +95,7 @@ proc getCurrOwner(c: PTransf): PSym =
|
||||
|
||||
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
|
||||
let r = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
||||
r.typ = skipTypes(typ, {tyGenericInst})
|
||||
r.typ = typ #skipTypes(typ, {tyGenericInst})
|
||||
incl(r.flags, sfFromGeneric)
|
||||
let owner = getCurrOwner(c)
|
||||
if owner.isIterator and not c.tooEarly:
|
||||
@@ -204,14 +204,8 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
||||
if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
|
||||
if it.sons[0].kind != nkSym:
|
||||
internalError(it.info, "transformConstSection")
|
||||
if sfFakeConst in it[0].sym.flags:
|
||||
var b = newNodeI(nkConstDef, it.info)
|
||||
addSon(b, it[0])
|
||||
addSon(b, ast.emptyNode) # no type description
|
||||
addSon(b, transform(c, it[2]).PNode)
|
||||
result[i] = PTransNode(b)
|
||||
else:
|
||||
result[i] = PTransNode(it)
|
||||
|
||||
result[i] = PTransNode(it)
|
||||
|
||||
proc hasContinue(n: PNode): bool =
|
||||
case n.kind
|
||||
@@ -414,8 +408,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
result = newTransNode(nkChckRange, n, 3)
|
||||
dest = skipTypes(n.typ, abstractVar)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
|
||||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode
|
||||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode
|
||||
of tyFloat..tyFloat128:
|
||||
# XXX int64 -> float conversion?
|
||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||
@@ -480,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
|
||||
type
|
||||
TPutArgInto = enum
|
||||
paDirectMapping, paFastAsgn, paVarAsgn
|
||||
paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
|
||||
|
||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
# This analyses how to treat the mapping "formal <-> arg" in an
|
||||
# inline context.
|
||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
if arg.kind == nkStmtListExpr:
|
||||
return paComplexOpenarray
|
||||
return paDirectMapping # XXX really correct?
|
||||
# what if ``arg`` has side-effects?
|
||||
case arg.kind
|
||||
@@ -575,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||
idNodeTablePut(newC.mapping, formal, arg)
|
||||
# XXX BUG still not correct if the arg has a side effect!
|
||||
of paComplexOpenarray:
|
||||
let typ = newType(tySequence, formal.owner)
|
||||
addSonSkipIntLit(typ, formal.typ.sons[0])
|
||||
var temp = newTemp(c, typ, formal.info)
|
||||
addVar(v, temp)
|
||||
add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
|
||||
var body = iter.getBody.copyTree
|
||||
pushInfoContext(n.info)
|
||||
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
||||
|
||||
@@ -103,14 +103,16 @@ proc getMagic*(op: PNode): TMagic =
|
||||
else: result = mNone
|
||||
else: result = mNone
|
||||
|
||||
proc treeToSym*(t: PNode): PSym =
|
||||
result = t.sym
|
||||
|
||||
proc isConstExpr*(n: PNode): bool =
|
||||
result = (n.kind in
|
||||
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
|
||||
|
||||
proc isCaseObj*(n: PNode): bool =
|
||||
if n.kind == nkRecCase: return true
|
||||
for i in 0..<safeLen(n):
|
||||
if n[i].isCaseObj: return true
|
||||
|
||||
proc isDeepConstExpr*(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
@@ -119,11 +121,14 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = isDeepConstExpr(n.sons[1])
|
||||
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
|
||||
for i in 0 .. <n.len:
|
||||
for i in ord(n.kind == nkObjConstr) .. <n.len:
|
||||
if not isDeepConstExpr(n.sons[i]): return false
|
||||
# XXX once constant objects are supported by the codegen this needs to be
|
||||
# weakened:
|
||||
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
|
||||
if n.typ.isNil: result = true
|
||||
else:
|
||||
let t = n.typ.skipTypes({tyGenericInst, tyDistinct})
|
||||
if t.kind in {tyRef, tyPtr}: return false
|
||||
if t.kind != tyObject or not isCaseObj(t.n):
|
||||
result = true
|
||||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
||||
|
||||
@@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool
|
||||
proc enumHasHoles*(t: PType): bool
|
||||
|
||||
const
|
||||
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
|
||||
# replace with typedescX
|
||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||
tyConst, tyMutable, tyTypeDesc}
|
||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
||||
@@ -61,6 +63,7 @@ const
|
||||
|
||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
|
||||
tyTypeDesc}
|
||||
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||
typedescInst* = abstractInst + {tyTypeDesc}
|
||||
|
||||
@@ -148,10 +151,12 @@ proc skipGeneric(t: PType): PType =
|
||||
|
||||
proc isOrdinalType(t: PType): bool =
|
||||
assert(t != nil)
|
||||
# caution: uint, uint64 are no ordinal types!
|
||||
result = t.kind in {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} or
|
||||
(t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
|
||||
isOrdinalType(t.sons[0])
|
||||
const
|
||||
# caution: uint, uint64 are no ordinal types!
|
||||
baseKinds = {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum}
|
||||
parentKinds = {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst,
|
||||
tyDistinct}
|
||||
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
|
||||
|
||||
proc enumHasHoles(t: PType): bool =
|
||||
var b = t
|
||||
@@ -407,7 +412,8 @@ const
|
||||
"!", "varargs[$1]", "iter[$1]", "Error Type",
|
||||
"BuiltInTypeClass", "UserTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
|
||||
"void"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
|
||||
|
||||
@@ -540,7 +546,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
else:
|
||||
result.add typeToString(t.sons[0])
|
||||
of tyRange:
|
||||
result = "range " & rangeToStr(t.n)
|
||||
result = "range "
|
||||
if t.n != nil and t.n.kind == nkRange:
|
||||
result.add rangeToStr(t.n)
|
||||
if prefer != preferExported:
|
||||
result.add("(" & typeToString(t.sons[0]) & ")")
|
||||
of tyProc:
|
||||
@@ -727,6 +735,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
|
||||
result = paramsNotEqual
|
||||
|
||||
proc sameConstraints(a, b: PNode): bool =
|
||||
if isNil(a) and isNil(b): return true
|
||||
internalAssert a.len == b.len
|
||||
for i in 1 .. <a.len:
|
||||
if not exprStructuralEquivalent(a[i].sym.constraint,
|
||||
@@ -799,8 +808,10 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
||||
result = x.name.id == y.name.id
|
||||
if not result: break
|
||||
else: internalError(a.n.info, "sameTuple")
|
||||
elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
|
||||
result = false
|
||||
|
||||
template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
|
||||
template ifFastObjectTypeCheckFailed(a, b: PType, body: untyped) =
|
||||
if tfFromGeneric notin a.flags + b.flags:
|
||||
# fast case: id comparison suffices:
|
||||
result = a.id == b.id
|
||||
@@ -908,7 +919,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
while a.kind == tyDistinct: a = a.sons[0]
|
||||
if a.kind != b.kind: return false
|
||||
|
||||
if x.kind == tyGenericInst:
|
||||
# this is required by tunique_type but makes no sense really:
|
||||
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
|
||||
let
|
||||
lhs = x.skipGenericAlias
|
||||
rhs = y.skipGenericAlias
|
||||
@@ -922,7 +934,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
|
||||
case a.kind
|
||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||
tyInt..tyBigNum, tyStmt, tyExpr:
|
||||
tyInt..tyBigNum, tyStmt, tyExpr, tyVoid:
|
||||
result = sameFlags(a, b)
|
||||
of tyStatic, tyFromExpr:
|
||||
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
|
||||
@@ -1108,7 +1120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
result = nil
|
||||
of tyExpr, tyStmt, tyStatic:
|
||||
if kind notin {skParam, skResult}: result = t
|
||||
of tyEmpty:
|
||||
of tyVoid:
|
||||
if taField notin flags: result = t
|
||||
of tyTypeClasses:
|
||||
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
||||
@@ -1153,7 +1165,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
if result != nil: break
|
||||
if result.isNil and t.n != nil:
|
||||
result = typeAllowedNode(marker, t.n, kind, flags)
|
||||
of tyProxy:
|
||||
of tyProxy, tyEmpty:
|
||||
# for now same as error node; we say it's a valid type as it should
|
||||
# prevent cascading errors:
|
||||
result = nil
|
||||
@@ -1313,6 +1325,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
||||
of tyTypeDesc:
|
||||
result = computeSizeAux(typ.base, a)
|
||||
of tyForward: return szIllegalRecursion
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
|
||||
else: result = szUnknownSize
|
||||
else:
|
||||
#internalError("computeSizeAux()")
|
||||
result = szUnknownSize
|
||||
@@ -1448,6 +1463,18 @@ proc skipConv*(n: PNode): PNode =
|
||||
result = n.sons[1]
|
||||
else: discard
|
||||
|
||||
proc skipHidden*(n: PNode): PNode =
|
||||
result = n
|
||||
while true:
|
||||
case result.kind
|
||||
of nkHiddenStdConv, nkHiddenSubConv:
|
||||
if result.sons[1].typ.classify == result.typ.classify:
|
||||
result = result.sons[1]
|
||||
else: break
|
||||
of nkHiddenDeref, nkHiddenAddr:
|
||||
result = result.sons[0]
|
||||
else: break
|
||||
|
||||
proc skipConvTakeType*(n: PNode): PNode =
|
||||
result = n.skipConv
|
||||
result.typ = n.typ
|
||||
@@ -1493,3 +1520,12 @@ proc skipHiddenSubConv*(n: PNode): PNode =
|
||||
result.typ = dest
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc typeMismatch*(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
let named = typeToString(formal)
|
||||
let desc = typeToString(formal, preferDesc)
|
||||
let x = if named == desc: named else: named & " = " & desc
|
||||
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [x]))
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
## This file implements the new evaluation engine for Nim code.
|
||||
## An instruction is 1-3 int32s in memory, it is a register based VM.
|
||||
|
||||
const debugEchoCode = false
|
||||
const
|
||||
debugEchoCode = false
|
||||
traceCode = debugEchoCode
|
||||
|
||||
import ast except getstr
|
||||
|
||||
@@ -90,38 +92,38 @@ when not defined(nimComputedGoto):
|
||||
|
||||
proc myreset(n: var TFullReg) = reset(n)
|
||||
|
||||
template ensureKind(k: expr) {.immediate, dirty.} =
|
||||
template ensureKind(k: untyped) {.dirty.} =
|
||||
if regs[ra].kind != k:
|
||||
myreset(regs[ra])
|
||||
regs[ra].kind = k
|
||||
|
||||
template decodeB(k: expr) {.immediate, dirty.} =
|
||||
template decodeB(k: untyped) {.dirty.} =
|
||||
let rb = instr.regB
|
||||
ensureKind(k)
|
||||
|
||||
template decodeBC(k: expr) {.immediate, dirty.} =
|
||||
template decodeBC(k: untyped) {.dirty.} =
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
ensureKind(k)
|
||||
|
||||
template declBC() {.immediate, dirty.} =
|
||||
template declBC() {.dirty.} =
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
|
||||
template decodeBImm(k: expr) {.immediate, dirty.} =
|
||||
template decodeBImm(k: untyped) {.dirty.} =
|
||||
let rb = instr.regB
|
||||
let imm = instr.regC - byteExcess
|
||||
ensureKind(k)
|
||||
|
||||
template decodeBx(k: expr) {.immediate, dirty.} =
|
||||
template decodeBx(k: untyped) {.dirty.} =
|
||||
let rbx = instr.regBx - wordExcess
|
||||
ensureKind(k)
|
||||
|
||||
template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
|
||||
template move(a, b: untyped) {.dirty.} = system.shallowCopy(a, b)
|
||||
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
||||
|
||||
proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
||||
if x.node.isNil:
|
||||
if x.node.isNil or not keepNode:
|
||||
x.node = newNode(nkStrLit)
|
||||
elif x.node.kind == nkNilLit and keepNode:
|
||||
when defined(useNodeIds):
|
||||
@@ -160,7 +162,7 @@ proc moveConst(x: var TFullReg, y: TFullReg) =
|
||||
|
||||
# this seems to be the best way to model the reference semantics
|
||||
# of system.NimNode:
|
||||
template asgnRef(x, y: expr) = moveConst(x, y)
|
||||
template asgnRef(x, y: untyped) = moveConst(x, y)
|
||||
|
||||
proc copyValue(src: PNode): PNode =
|
||||
if src == nil or nfIsRef in src.flags:
|
||||
@@ -231,7 +233,7 @@ proc regToNode(x: TFullReg): PNode =
|
||||
of rkRegisterAddr: result = regToNode(x.regAddr[])
|
||||
of rkNodeAddr: result = x.nodeAddr[]
|
||||
|
||||
template getstr(a: expr): expr =
|
||||
template getstr(a: untyped): untyped =
|
||||
(if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
|
||||
|
||||
proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||
@@ -404,7 +406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let instr = c.code[pc]
|
||||
let ra = instr.regA
|
||||
#if c.traceActive:
|
||||
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
|
||||
when traceCode:
|
||||
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
|
||||
# message(c.debug[pc], warnUser, "Trace")
|
||||
|
||||
case instr.opcode
|
||||
@@ -542,7 +545,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[rb].node.kind == nkRefTy:
|
||||
regs[ra].node = regs[rb].node.sons[0]
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'")
|
||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
|
||||
else:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
of opcWrDeref:
|
||||
@@ -1182,19 +1185,35 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNGetType:
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
if rc == 0:
|
||||
case rc:
|
||||
of 0:
|
||||
# getType opcode:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
else:
|
||||
of 1:
|
||||
# typeKind opcode:
|
||||
ensureKind(rkInt)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].intVal = ord(regs[rb].node.typ.kind)
|
||||
#else:
|
||||
# stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
of 2:
|
||||
# getTypeInst opcode:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
else:
|
||||
# getTypeImpl opcode:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
of opcNStrVal:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
@@ -1554,7 +1573,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
var evalMacroCounter: int
|
||||
|
||||
proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||
# XXX GlobalError() is ugly here, but I don't know a better solution for now
|
||||
# XXX globalError() is ugly here, but I don't know a better solution for now
|
||||
inc(evalMacroCounter)
|
||||
if evalMacroCounter > 100:
|
||||
globalError(n.info, errTemplateInstantiationTooNested)
|
||||
@@ -1584,7 +1603,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||
|
||||
# return value:
|
||||
tos.slots[0].kind = rkNode
|
||||
tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
|
||||
tos.slots[0].node = newNodeI(nkEmpty, n.info)
|
||||
|
||||
# setup parameters:
|
||||
for i in 1.. <sym.typ.len:
|
||||
@@ -1604,4 +1623,3 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
#debug result
|
||||
|
||||
@@ -230,10 +230,10 @@ const
|
||||
slotSomeTemp* = slotTempUnknown
|
||||
relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
|
||||
|
||||
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
|
||||
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
|
||||
template regB*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
|
||||
template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32)
|
||||
template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int
|
||||
template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32)
|
||||
template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
|
||||
template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
|
||||
template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32)
|
||||
template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int
|
||||
|
||||
template jmpDiff*(x: TInstr): int {.immediate.} = regBx(x) - wordExcess
|
||||
template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, types, msgs, osproc, streams, options, idents, securehash
|
||||
import ast, types, msgs, os, osproc, streams, options, idents, securehash
|
||||
|
||||
proc readOutput(p: Process): string =
|
||||
result = ""
|
||||
@@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string =
|
||||
|
||||
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
try:
|
||||
let filename = file.findFile
|
||||
var filename = parentDir(info.toFullPath) / file
|
||||
if not fileExists(filename):
|
||||
filename = file.findFile
|
||||
result = readFile(filename)
|
||||
# we produce a fake include statement for every slurped filename, so that
|
||||
# the module dependencies are accurate:
|
||||
@@ -61,123 +63,249 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
localError(info, errCannotOpenFile, file)
|
||||
result = ""
|
||||
|
||||
proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
|
||||
proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
|
||||
let sym = newSym(skType, getIdent(name), t.owner, info)
|
||||
sym.magic = m
|
||||
sym.typ = t
|
||||
result = newSymNode(sym)
|
||||
result.typ = t
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
|
||||
proc mapTypeToAstX(t: PType; info: TLineInfo;
|
||||
inst=false; allowRecursionX=false): PNode
|
||||
|
||||
proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
|
||||
proc mapTypeToBracketX(name: string; m: TMagic; t: PType; info: TLineInfo;
|
||||
inst=false): PNode =
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicTypeX(name, t, info)
|
||||
result.add atomicTypeX(name, m, t, info)
|
||||
for i in 0 .. < t.len:
|
||||
if t.sons[i] == nil:
|
||||
let void = atomicTypeX("void", t, info)
|
||||
void.typ = newType(tyEmpty, t.owner)
|
||||
let void = atomicTypeX("void", mVoid, t, info)
|
||||
void.typ = newType(tyVoid, t.owner)
|
||||
result.add void
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
result.add mapTypeToAstX(t.sons[i], info, inst)
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
|
||||
template atomicType(name): expr = atomicTypeX(name, t, info)
|
||||
proc objectNode(n: PNode): PNode =
|
||||
if n.kind == nkSym:
|
||||
result = newNodeI(nkIdentDefs, n.info)
|
||||
result.add n # name
|
||||
result.add mapTypeToAstX(n.sym.typ, n.info, true, false) # type
|
||||
result.add ast.emptyNode # no assigned value
|
||||
else:
|
||||
result = copyNode(n)
|
||||
for i in 0 ..< n.safeLen:
|
||||
result.add objectNode(n[i])
|
||||
|
||||
proc mapTypeToAstX(t: PType; info: TLineInfo;
|
||||
inst=false; allowRecursionX=false): PNode =
|
||||
var allowRecursion = allowRecursionX
|
||||
template atomicType(name, m): untyped = atomicTypeX(name, m, t, info)
|
||||
template mapTypeToAst(t,info): untyped = mapTypeToAstX(t, info, inst)
|
||||
template mapTypeToAstR(t,info): untyped = mapTypeToAstX(t, info, inst, true)
|
||||
template mapTypeToAst(t,i,info): untyped =
|
||||
if i<t.len and t.sons[i]!=nil: mapTypeToAstX(t.sons[i], info, inst)
|
||||
else: ast.emptyNode
|
||||
template mapTypeToBracket(name, m, t, info): untyped =
|
||||
mapTypeToBracketX(name, m, t, info, inst)
|
||||
template newNodeX(kind): untyped =
|
||||
newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
|
||||
template newIdent(s): untyped =
|
||||
var r = newNodeX(nkIdent)
|
||||
r.add !s
|
||||
r
|
||||
template newIdentDefs(n,t): untyped =
|
||||
var id = newNodeX(nkIdentDefs)
|
||||
id.add n # name
|
||||
id.add mapTypeToAst(t, info) # type
|
||||
id.add ast.emptyNode # no assigned value
|
||||
id
|
||||
template newIdentDefs(s): untyped = newIdentDefs(s, s.typ)
|
||||
|
||||
if inst:
|
||||
if t.sym != nil: # if this node has a symbol
|
||||
if allowRecursion: # getTypeImpl behavior: turn off recursion
|
||||
allowRecursion = false
|
||||
else: # getTypeInst behavior: return symbol
|
||||
return atomicType(t.sym.name.s, t.sym.magic)
|
||||
|
||||
case t.kind
|
||||
of tyNone: result = atomicType("none")
|
||||
of tyBool: result = atomicType("bool")
|
||||
of tyChar: result = atomicType("char")
|
||||
of tyNil: result = atomicType("nil")
|
||||
of tyExpr: result = atomicType("expr")
|
||||
of tyStmt: result = atomicType("stmt")
|
||||
of tyEmpty: result = atomicType"void"
|
||||
of tyNone: result = atomicType("none", mNone)
|
||||
of tyBool: result = atomicType("bool", mBool)
|
||||
of tyChar: result = atomicType("char", mChar)
|
||||
of tyNil: result = atomicType("nil", mNil)
|
||||
of tyExpr: result = atomicType("expr", mExpr)
|
||||
of tyStmt: result = atomicType("stmt", mStmt)
|
||||
of tyVoid: result = atomicType("void", mVoid)
|
||||
of tyEmpty: result = atomicType("empty", mNone)
|
||||
of tyArrayConstr, tyArray:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("array")
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add atomicType("array", mArray)
|
||||
if inst and t.sons[0].kind == tyRange:
|
||||
var rng = newNodeX(nkInfix)
|
||||
rng.add newIdentNode(getIdent(".."), info)
|
||||
rng.add t.sons[0].n.sons[0].copyTree
|
||||
rng.add t.sons[0].n.sons[1].copyTree
|
||||
result.add rng
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add mapTypeToAst(t.sons[1], info)
|
||||
of tyTypeDesc:
|
||||
if t.base != nil:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("typeDesc")
|
||||
result.add atomicType("typeDesc", mTypeDesc)
|
||||
result.add mapTypeToAst(t.base, info)
|
||||
else:
|
||||
result = atomicType"typeDesc"
|
||||
result = atomicType("typeDesc", mTypeDesc)
|
||||
of tyGenericInvocation:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
for i in 0 .. < t.len:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
|
||||
of tyGenericInst:
|
||||
if inst:
|
||||
if allowRecursion:
|
||||
result = mapTypeToAstR(t.lastSon, info)
|
||||
else:
|
||||
result = newNodeX(nkBracketExpr)
|
||||
result.add mapTypeToAst(t.lastSon, info)
|
||||
for i in 1 .. < t.len-1:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
else:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
of tyDistinct:
|
||||
if allowRecursion:
|
||||
result = mapTypeToBracket("distinct", t, info)
|
||||
if inst:
|
||||
result = newNodeX(nkDistinctTy)
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
else:
|
||||
result = atomicType(t.sym.name.s)
|
||||
of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
|
||||
of tyObject:
|
||||
if allowRecursion:
|
||||
result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
|
||||
if t.sons[0] == nil:
|
||||
result.add ast.emptyNode
|
||||
if allowRecursion or t.sym == nil:
|
||||
result = mapTypeToBracket("distinct", mDistinct, t, info)
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add copyTree(t.n)
|
||||
result = atomicType(t.sym.name.s, t.sym.magic)
|
||||
of tyGenericParam, tyForward:
|
||||
result = atomicType(t.sym.name.s, t.sym.magic)
|
||||
of tyObject:
|
||||
if inst:
|
||||
result = newNodeX(nkObjectTy)
|
||||
result.add ast.emptyNode # pragmas not reconstructed yet
|
||||
if t.sons[0] == nil: result.add ast.emptyNode # handle parent object
|
||||
else:
|
||||
var nn = newNodeX(nkOfInherit)
|
||||
nn.add mapTypeToAst(t.sons[0], info)
|
||||
result.add nn
|
||||
if t.n.len > 0:
|
||||
result.add objectNode(t.n)
|
||||
else:
|
||||
result.add ast.emptyNode
|
||||
else:
|
||||
result = atomicType(t.sym.name.s)
|
||||
if allowRecursion or t.sym == nil:
|
||||
result = newNodeIT(nkObjectTy, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add ast.emptyNode
|
||||
if t.sons[0] == nil:
|
||||
result.add ast.emptyNode
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add copyTree(t.n)
|
||||
else:
|
||||
result = atomicType(t.sym.name.s, t.sym.magic)
|
||||
of tyEnum:
|
||||
result = newNodeIT(nkEnumTy, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add copyTree(t.n)
|
||||
of tyTuple: result = mapTypeToBracket("tuple", t, info)
|
||||
of tySet: result = mapTypeToBracket("set", t, info)
|
||||
of tyPtr: result = mapTypeToBracket("ptr", t, info)
|
||||
of tyRef: result = mapTypeToBracket("ref", t, info)
|
||||
of tyVar: result = mapTypeToBracket("var", t, info)
|
||||
of tySequence: result = mapTypeToBracket("seq", t, info)
|
||||
of tyProc: result = mapTypeToBracket("proc", t, info)
|
||||
of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
|
||||
of tyTuple:
|
||||
if inst:
|
||||
result = newNodeX(nkTupleTy)
|
||||
for s in t.n.sons:
|
||||
result.add newIdentDefs(s)
|
||||
else:
|
||||
result = mapTypeToBracket("tuple", mTuple, t, info)
|
||||
of tySet: result = mapTypeToBracket("set", mSet, t, info)
|
||||
of tyPtr:
|
||||
if inst:
|
||||
result = newNodeX(nkPtrTy)
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
else:
|
||||
result = mapTypeToBracket("ptr", mPtr, t, info)
|
||||
of tyRef:
|
||||
if inst:
|
||||
result = newNodeX(nkRefTy)
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
else:
|
||||
result = mapTypeToBracket("ref", mRef, t, info)
|
||||
of tyVar: result = mapTypeToBracket("var", mVar, t, info)
|
||||
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
|
||||
of tyProc:
|
||||
if inst:
|
||||
result = newNodeX(nkProcTy)
|
||||
var fp = newNodeX(nkFormalParams)
|
||||
if t.sons[0] == nil:
|
||||
fp.add ast.emptyNode
|
||||
else:
|
||||
fp.add mapTypeToAst(t.sons[0], t.n[0].info)
|
||||
for i in 1..<t.sons.len:
|
||||
fp.add newIdentDefs(t.n[i], t.sons[i])
|
||||
result.add fp
|
||||
result.add ast.emptyNode # pragmas aren't reconstructed yet
|
||||
else:
|
||||
result = mapTypeToBracket("proc", mNone, t, info)
|
||||
of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info)
|
||||
of tyRange:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("range")
|
||||
result.add atomicType("range", mRange)
|
||||
result.add t.n.sons[0].copyTree
|
||||
result.add t.n.sons[1].copyTree
|
||||
of tyPointer: result = atomicType"pointer"
|
||||
of tyString: result = atomicType"string"
|
||||
of tyCString: result = atomicType"cstring"
|
||||
of tyInt: result = atomicType"int"
|
||||
of tyInt8: result = atomicType"int8"
|
||||
of tyInt16: result = atomicType"int16"
|
||||
of tyInt32: result = atomicType"int32"
|
||||
of tyInt64: result = atomicType"int64"
|
||||
of tyFloat: result = atomicType"float"
|
||||
of tyFloat32: result = atomicType"float32"
|
||||
of tyFloat64: result = atomicType"float64"
|
||||
of tyFloat128: result = atomicType"float128"
|
||||
of tyUInt: result = atomicType"uint"
|
||||
of tyUInt8: result = atomicType"uint8"
|
||||
of tyUInt16: result = atomicType"uint16"
|
||||
of tyUInt32: result = atomicType"uint32"
|
||||
of tyUInt64: result = atomicType"uint64"
|
||||
of tyBigNum: result = atomicType"bignum"
|
||||
of tyConst: result = mapTypeToBracket("const", t, info)
|
||||
of tyMutable: result = mapTypeToBracket("mutable", t, info)
|
||||
of tyVarargs: result = mapTypeToBracket("varargs", t, info)
|
||||
of tyIter: result = mapTypeToBracket("iter", t, info)
|
||||
of tyProxy: result = atomicType"error"
|
||||
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
|
||||
of tyPointer: result = atomicType("pointer", mPointer)
|
||||
of tyString: result = atomicType("string", mString)
|
||||
of tyCString: result = atomicType("cstring", mCString)
|
||||
of tyInt: result = atomicType("int", mInt)
|
||||
of tyInt8: result = atomicType("int8", mInt8)
|
||||
of tyInt16: result = atomicType("int16", mInt16)
|
||||
of tyInt32: result = atomicType("int32", mInt32)
|
||||
of tyInt64: result = atomicType("int64", mInt64)
|
||||
of tyFloat: result = atomicType("float", mFloat)
|
||||
of tyFloat32: result = atomicType("float32", mFloat32)
|
||||
of tyFloat64: result = atomicType("float64", mFloat64)
|
||||
of tyFloat128: result = atomicType("float128", mFloat128)
|
||||
of tyUInt: result = atomicType("uint", mUint)
|
||||
of tyUInt8: result = atomicType("uint8", mUint8)
|
||||
of tyUInt16: result = atomicType("uint16", mUint16)
|
||||
of tyUInt32: result = atomicType("uint32", mUint32)
|
||||
of tyUInt64: result = atomicType("uint64", mUint64)
|
||||
of tyBigNum: result = atomicType("bignum", mNone)
|
||||
of tyConst: result = mapTypeToBracket("const", mNone, t, info)
|
||||
of tyMutable: result = mapTypeToBracket("mutable", mNone, t, info)
|
||||
of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
|
||||
of tyIter: result = mapTypeToBracket("iter", mNone, t, info)
|
||||
of tyProxy: result = atomicType("error", mNone)
|
||||
of tyBuiltInTypeClass:
|
||||
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
|
||||
of tyUserTypeClass:
|
||||
result = mapTypeToBracket("concept", t, info)
|
||||
result = mapTypeToBracket("concept", mNone, t, info)
|
||||
result.add t.n.copyTree
|
||||
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", t, info)
|
||||
of tyNot: result = mapTypeToBracket("not", t, info)
|
||||
of tyAnything: result = atomicType"anything"
|
||||
of tyCompositeTypeClass:
|
||||
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", mOr, t, info)
|
||||
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
|
||||
of tyAnything: result = atomicType("anything", mNone)
|
||||
of tyStatic, tyFromExpr, tyFieldAccessor:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("static")
|
||||
if t.n != nil:
|
||||
result.add t.n.copyTree
|
||||
if inst:
|
||||
if t.n != nil: result = t.n.copyTree
|
||||
else: result = atomicType("void", mVoid)
|
||||
else:
|
||||
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
|
||||
result.add atomicType("static", mNone)
|
||||
if t.n != nil:
|
||||
result.add t.n.copyTree
|
||||
|
||||
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
|
||||
result = mapTypeToAst(t, info, true)
|
||||
result = mapTypeToAstX(t, info, false, true)
|
||||
|
||||
# the "Inst" version includes generic parameters in the resulting type tree
|
||||
# and also tries to look like the corresponding Nim type declaration
|
||||
proc opMapTypeInstToAst*(t: PType; info: TLineInfo): PNode =
|
||||
result = mapTypeToAstX(t, info, true, false)
|
||||
|
||||
# the "Impl" version includes generic parameters in the resulting type tree
|
||||
# and also tries to look like the corresponding Nim type implementation
|
||||
proc opMapTypeImplToAst*(t: PType; info: TLineInfo): PNode =
|
||||
result = mapTypeToAstX(t, info, true, true)
|
||||
|
||||
@@ -102,6 +102,10 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||
let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
|
||||
(b.uint32 shl 16'u32) or
|
||||
(c.uint32 shl 24'u32)).TInstr
|
||||
when false:
|
||||
if ctx.code.len == 43:
|
||||
writeStackTrace()
|
||||
echo "generating ", opc
|
||||
ctx.code.add(ins)
|
||||
ctx.debug.add(n.info)
|
||||
|
||||
@@ -122,6 +126,11 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
|
||||
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
|
||||
# Applies `opc` to `bx` and stores it into register `a`
|
||||
# `bx` must be signed and in the range [-32768, 32767]
|
||||
when false:
|
||||
if c.code.len == 43:
|
||||
writeStackTrace()
|
||||
echo "generating ", opc
|
||||
|
||||
if bx >= -32768 and bx <= 32767:
|
||||
let ins = (opc.uint32 or a.uint32 shl 8'u32 or
|
||||
(bx+wordExcess).uint32 shl 16'u32).TInstr
|
||||
@@ -222,7 +231,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
|
||||
proc freeTempRange(c: PCtx; start: TRegister, n: int) =
|
||||
for i in start .. start+n-1: c.freeTemp(TRegister(i))
|
||||
|
||||
template withTemp(tmp, typ: expr, body: stmt) {.immediate, dirty.} =
|
||||
template withTemp(tmp, typ, body: untyped) {.dirty.} =
|
||||
var tmp = getTemp(c, typ)
|
||||
body
|
||||
c.freeTemp(tmp)
|
||||
@@ -232,7 +241,7 @@ proc popBlock(c: PCtx; oldLen: int) =
|
||||
c.patch(f)
|
||||
c.prc.blocks.setLen(oldLen)
|
||||
|
||||
template withBlock(labl: PSym; body: stmt) {.immediate, dirty.} =
|
||||
template withBlock(labl: PSym; body: untyped) {.dirty.} =
|
||||
var oldLen {.gensym.} = c.prc.blocks.len
|
||||
c.prc.blocks.add TBlock(label: labl, fixups: @[])
|
||||
body
|
||||
@@ -258,7 +267,7 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
||||
proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
|
||||
# stmt is different from 'void' in meta programming contexts.
|
||||
# So we only set dest to -1 if 'void':
|
||||
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
|
||||
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyVoid):
|
||||
c.freeTemp(dest)
|
||||
dest = -1
|
||||
|
||||
@@ -365,7 +374,7 @@ proc canonValue*(n: PNode): PNode =
|
||||
|
||||
proc rawGenLiteral(c: PCtx; n: PNode): int =
|
||||
result = c.constants.len
|
||||
assert(n.kind != nkCall)
|
||||
#assert(n.kind != nkCall)
|
||||
n.flags.incl nfAllConst
|
||||
c.constants.add n.canonValue
|
||||
internalAssert result < 0x7fff
|
||||
@@ -488,12 +497,30 @@ proc genReturn(c: PCtx; n: PNode) =
|
||||
gen(c, n.sons[0])
|
||||
c.gABC(n, opcRet)
|
||||
|
||||
|
||||
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# opcLdConst is now always valid. We produce the necessary copy in the
|
||||
# assignments now:
|
||||
#var opc = opcLdConst
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
|
||||
let lit = genLiteral(c, n)
|
||||
c.gABx(n, opcLdConst, dest, lit)
|
||||
|
||||
proc genCall(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# it can happen that due to inlining we have a 'n' that should be
|
||||
# treated as a constant (see issue #537).
|
||||
#if n.typ != nil and n.typ.sym != nil and n.typ.sym.magic == mPNimrodNode:
|
||||
# genLit(c, n, dest)
|
||||
# return
|
||||
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
|
||||
let x = c.getTempRange(n.len, slotTempUnknown)
|
||||
# varargs need 'opcSetType' for the FFI support:
|
||||
let fntyp = n.sons[0].typ
|
||||
let fntyp = skipTypes(n.sons[0].typ, abstractInst)
|
||||
for i in 0.. <n.len:
|
||||
#if i > 0 and i < sonsLen(fntyp):
|
||||
# let paramType = fntyp.n.sons[i]
|
||||
# if paramType.typ.isCompileTimeOnly: continue
|
||||
var r: TRegister = x+i
|
||||
c.gen(n.sons[i], r)
|
||||
if i >= fntyp.len:
|
||||
@@ -570,16 +597,27 @@ proc genNew(c: PCtx; n: PNode) =
|
||||
c.freeTemp(dest)
|
||||
|
||||
proc genNewSeq(c: PCtx; n: PNode) =
|
||||
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
|
||||
let t = n.sons[1].typ
|
||||
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(t)
|
||||
else: c.genx(n.sons[1])
|
||||
let tmp = c.genx(n.sons[2])
|
||||
c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(
|
||||
c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
|
||||
abstractVar-{tyTypeDesc})))
|
||||
c.gABx(n, opcNewSeq, tmp, 0)
|
||||
c.freeTemp(tmp)
|
||||
c.genAsgnPatch(n.sons[1], dest)
|
||||
c.freeTemp(dest)
|
||||
|
||||
proc genNewSeqOfCap(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let t = n.typ
|
||||
let tmp = c.getTemp(n.sons[1].typ)
|
||||
c.gABx(n, opcLdNull, dest, c.genType(t))
|
||||
c.gABx(n, opcLdImmInt, tmp, 0)
|
||||
c.gABx(n, opcNewSeq, dest, c.genType(t.skipTypes(
|
||||
abstractVar-{tyTypeDesc})))
|
||||
c.gABx(n, opcNewSeq, tmp, 0)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
let tmp = c.genx(n.sons[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -626,8 +664,7 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
||||
(t.kind == tyInt and t.size == 4):
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
|
||||
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
@@ -704,6 +741,10 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
c.genNarrow(n, dest)
|
||||
|
||||
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||
if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc:
|
||||
# don't do anything for lambda lifting conversions:
|
||||
gen(c, arg, dest)
|
||||
return
|
||||
let tmp = c.genx(arg)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opc, dest, tmp)
|
||||
@@ -751,6 +792,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mNewSeq:
|
||||
unused(n, dest)
|
||||
c.genNewSeq(n)
|
||||
of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
|
||||
of mNewString:
|
||||
genUnaryABC(c, n, dest, opcNewStr)
|
||||
# XXX buggy
|
||||
@@ -804,7 +846,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
|
||||
of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)
|
||||
of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
|
||||
of mEqProc, mEqRef, mEqUntracedRef, mEqCString:
|
||||
of mEqProc, mEqRef, mEqUntracedRef:
|
||||
genBinaryABC(c, n, dest, opcEqRef)
|
||||
of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
|
||||
of mNot: genUnaryABC(c, n, dest, opcNot)
|
||||
@@ -821,7 +863,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
|
||||
mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
genConv(c, n, n.sons[1], dest)
|
||||
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
||||
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
|
||||
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
|
||||
@@ -970,7 +1012,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mNGetType:
|
||||
let tmp = c.genx(n.sons[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
|
||||
let rc = case n[0].sym.name.s:
|
||||
of "getType": 0
|
||||
of "typeKind": 1
|
||||
of "getTypeInst": 2
|
||||
else: 3 # "getTypeImpl"
|
||||
c.gABC(n, opcNGetType, dest, tmp, rc)
|
||||
c.freeTemp(tmp)
|
||||
#genUnaryABC(c, n, dest, opcNGetType)
|
||||
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
|
||||
@@ -1117,7 +1164,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
if isAddr and (let m = canElimAddr(n); m != nil):
|
||||
gen(c, m, dest, flags)
|
||||
return
|
||||
let newflags = if isAddr: flags+{gfAddrOf} else: flags
|
||||
|
||||
let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess}
|
||||
else: {gfAddrOf}
|
||||
let newflags = if isAddr: flags+af else: flags
|
||||
# consider:
|
||||
# proc foo(f: var ref int) =
|
||||
# f = new(int)
|
||||
@@ -1132,7 +1182,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
if gfAddrOf notin flags and fitsRegister(n.typ):
|
||||
c.gABC(n, opcNodeToReg, dest, dest)
|
||||
elif isAddr and isGlobal(n.sons[0]):
|
||||
gen(c, n.sons[0], dest, flags+{gfAddrOf})
|
||||
gen(c, n.sons[0], dest, flags+af)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[0], newflags)
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
@@ -1215,7 +1265,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
proc isTemp(c: PCtx; dest: TDest): bool =
|
||||
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
|
||||
|
||||
template needsAdditionalCopy(n): expr =
|
||||
template needsAdditionalCopy(n): untyped =
|
||||
not c.isTemp(dest) and not fitsRegister(n.typ)
|
||||
|
||||
proc skipDeref(n: PNode): PNode =
|
||||
@@ -1286,15 +1336,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
let dest = c.genx(le, {gfAddrOf})
|
||||
genAsgn(c, dest, ri, requiresCopy)
|
||||
|
||||
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# opcLdConst is now always valid. We produce the necessary copy in the
|
||||
# assignments now:
|
||||
#var opc = opcLdConst
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
#elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
|
||||
let lit = genLiteral(c, n)
|
||||
c.gABx(n, opcLdConst, dest, lit)
|
||||
|
||||
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
||||
var n = newNode(nkType)
|
||||
n.typ = t
|
||||
@@ -1321,10 +1362,11 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||
# var decls{.compileTime.}: seq[NimNode] = @[]
|
||||
let dest = c.getTemp(s.typ)
|
||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||
let tmp = c.genx(s.ast)
|
||||
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(tmp)
|
||||
if s.ast != nil:
|
||||
let tmp = c.genx(s.ast)
|
||||
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
let s = n.sym
|
||||
@@ -1361,7 +1403,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
# see tests/t99bott for an example that triggers it:
|
||||
cannotEval(n)
|
||||
|
||||
template needsRegLoad(): expr =
|
||||
template needsRegLoad(): untyped =
|
||||
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
|
||||
|
||||
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||
@@ -1447,12 +1489,12 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||
of tyObject:
|
||||
result = newNodeIT(nkObjConstr, info, t)
|
||||
result.add(newNodeIT(nkEmpty, info, t))
|
||||
getNullValueAux(t.n, result)
|
||||
# initialize inherited fields:
|
||||
var base = t.sons[0]
|
||||
while base != nil:
|
||||
getNullValueAux(skipTypes(base, skipPtrs).n, result)
|
||||
base = base.sons[0]
|
||||
getNullValueAux(t.n, result)
|
||||
of tyArray, tyArrayConstr:
|
||||
result = newNodeIT(nkBracket, info, t)
|
||||
for i in countup(0, int(lengthOrd(t)) - 1):
|
||||
@@ -1655,10 +1697,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of skType:
|
||||
genTypeLit(c, s.typ, dest)
|
||||
of skGenericParam:
|
||||
if c.prc.sym.kind == skMacro:
|
||||
if c.prc.sym != nil and c.prc.sym.kind == skMacro:
|
||||
genRdVar(c, n, dest, flags)
|
||||
else:
|
||||
internalError(n.info, "cannot generate code for: " & s.name.s)
|
||||
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
|
||||
else:
|
||||
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
|
||||
of nkCallKinds:
|
||||
@@ -1736,9 +1778,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of declarativeDefs:
|
||||
unused(n, dest)
|
||||
of nkLambdaKinds:
|
||||
let s = n.sons[namePos].sym
|
||||
discard genProc(c, s)
|
||||
genLit(c, n.sons[namePos], dest)
|
||||
#let s = n.sons[namePos].sym
|
||||
#discard genProc(c, s)
|
||||
genLit(c, newSymNode(n.sons[namePos].sym), dest)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
let
|
||||
tmp0 = c.genx(n.sons[0])
|
||||
@@ -1766,6 +1808,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
genConv(c, n, n.sons[1], dest, opcCast)
|
||||
else:
|
||||
globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
|
||||
of nkTypeOfExpr:
|
||||
genTypeLit(c, n.typ, dest)
|
||||
else:
|
||||
globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
|
||||
|
||||
@@ -1865,8 +1909,8 @@ proc optimizeJumps(c: PCtx; start: int) =
|
||||
else: discard
|
||||
|
||||
proc genProc(c: PCtx; s: PSym): int =
|
||||
let x = s.ast.sons[optimizedCodePos]
|
||||
if x.kind == nkEmpty:
|
||||
var x = s.ast.sons[miscPos]
|
||||
if x.kind == nkEmpty or x[0].kind == nkEmpty:
|
||||
#if s.name.s == "outterMacro" or s.name.s == "innerProc":
|
||||
# echo "GENERATING CODE FOR ", s.name.s
|
||||
let last = c.code.len-1
|
||||
@@ -1877,7 +1921,11 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
c.debug.setLen(last)
|
||||
#c.removeLastEof
|
||||
result = c.code.len+1 # skip the jump instruction
|
||||
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
||||
if x.kind == nkEmpty:
|
||||
x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode)
|
||||
else:
|
||||
x.sons[0] = newIntNode(nkIntLit, result)
|
||||
s.ast.sons[miscPos] = x
|
||||
# thanks to the jmp we can add top level statements easily and also nest
|
||||
# procs easily:
|
||||
let body = s.getBody
|
||||
@@ -1912,4 +1960,4 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
c.prc = oldPrc
|
||||
else:
|
||||
c.prc.maxSlots = s.offset
|
||||
result = x.intVal.int
|
||||
result = x[0].intVal.int
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
template setX(k, field) {.immediate, dirty.} =
|
||||
template setX(k, field) {.dirty.} =
|
||||
var s: seq[TFullReg]
|
||||
move(s, cast[seq[TFullReg]](a.slots))
|
||||
if s[a.ra].kind != k:
|
||||
@@ -48,7 +48,7 @@ proc setResult*(a: VmArgs; v: seq[string]) =
|
||||
for x in v: n.add newStrNode(nkStrLit, x)
|
||||
s[a.ra].node = n
|
||||
|
||||
template getX(k, field) {.immediate, dirty.} =
|
||||
template getX(k, field) {.dirty.} =
|
||||
doAssert i < a.rc-1
|
||||
let s = cast[seq[TFullReg]](a.slots)
|
||||
doAssert s[i+a.rb+1].kind == k
|
||||
|
||||
@@ -15,31 +15,36 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
|
||||
|
||||
from os import getEnv, existsEnv, dirExists, fileExists, walkDir
|
||||
|
||||
template mathop(op) {.immediate, dirty.} =
|
||||
template mathop(op) {.dirty.} =
|
||||
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
|
||||
|
||||
template osop(op) {.immediate, dirty.} =
|
||||
template osop(op) {.dirty.} =
|
||||
registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
|
||||
|
||||
template systemop(op) {.immediate, dirty.} =
|
||||
template systemop(op) {.dirty.} =
|
||||
registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
|
||||
|
||||
template wrap1f(op) {.immediate, dirty.} =
|
||||
template wrap1f_math(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, op(getFloat(a, 0)))
|
||||
mathop op
|
||||
|
||||
template wrap2f(op) {.immediate, dirty.} =
|
||||
template wrap2f_math(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
|
||||
mathop op
|
||||
|
||||
template wrap1s(op) {.immediate, dirty.} =
|
||||
template wrap1s_os(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, op(getString(a, 0)))
|
||||
osop op
|
||||
|
||||
template wrap2svoid(op) {.immediate, dirty.} =
|
||||
template wrap1s_system(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, op(getString(a, 0)))
|
||||
systemop op
|
||||
|
||||
template wrap2svoid_system(op) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
op(getString(a, 0), getString(a, 1))
|
||||
systemop op
|
||||
@@ -55,34 +60,35 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
|
||||
newStrNode(nkStrLit, f))
|
||||
|
||||
proc registerAdditionalOps*(c: PCtx) =
|
||||
wrap1f(sqrt)
|
||||
wrap1f(ln)
|
||||
wrap1f(log10)
|
||||
wrap1f(log2)
|
||||
wrap1f(exp)
|
||||
wrap1f(round)
|
||||
wrap1f(arccos)
|
||||
wrap1f(arcsin)
|
||||
wrap1f(arctan)
|
||||
wrap2f(arctan2)
|
||||
wrap1f(cos)
|
||||
wrap1f(cosh)
|
||||
wrap2f(hypot)
|
||||
wrap1f(sinh)
|
||||
wrap1f(sin)
|
||||
wrap1f(tan)
|
||||
wrap1f(tanh)
|
||||
wrap2f(pow)
|
||||
wrap1f(trunc)
|
||||
wrap1f(floor)
|
||||
wrap1f(ceil)
|
||||
wrap2f(fmod)
|
||||
wrap1f_math(sqrt)
|
||||
wrap1f_math(ln)
|
||||
wrap1f_math(log10)
|
||||
wrap1f_math(log2)
|
||||
wrap1f_math(exp)
|
||||
wrap1f_math(round)
|
||||
wrap1f_math(arccos)
|
||||
wrap1f_math(arcsin)
|
||||
wrap1f_math(arctan)
|
||||
wrap2f_math(arctan2)
|
||||
wrap1f_math(cos)
|
||||
wrap1f_math(cosh)
|
||||
wrap2f_math(hypot)
|
||||
wrap1f_math(sinh)
|
||||
wrap1f_math(sin)
|
||||
wrap1f_math(tan)
|
||||
wrap1f_math(tanh)
|
||||
wrap2f_math(pow)
|
||||
wrap1f_math(trunc)
|
||||
wrap1f_math(floor)
|
||||
wrap1f_math(ceil)
|
||||
wrap2f_math(fmod)
|
||||
|
||||
wrap1s(getEnv)
|
||||
wrap1s(existsEnv)
|
||||
wrap1s(dirExists)
|
||||
wrap1s(fileExists)
|
||||
wrap2svoid(writeFile)
|
||||
wrap1s_os(getEnv)
|
||||
wrap1s_os(existsEnv)
|
||||
wrap1s_os(dirExists)
|
||||
wrap1s_os(fileExists)
|
||||
wrap2svoid_system(writeFile)
|
||||
wrap1s_system(readFile)
|
||||
systemop getCurrentExceptionMsg
|
||||
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
|
||||
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
|
||||
|
||||
@@ -36,6 +36,7 @@ type
|
||||
wColon, wColonColon, wEquals, wDot, wDotDot,
|
||||
wStar, wMinus,
|
||||
wMagic, wThread, wFinal, wProfiler, wObjChecks,
|
||||
wIntDefine, wStrDefine,
|
||||
|
||||
wDestroy,
|
||||
|
||||
@@ -121,7 +122,7 @@ const
|
||||
|
||||
":", "::", "=", ".", "..",
|
||||
"*", "-",
|
||||
"magic", "thread", "final", "profiler", "objchecks",
|
||||
"magic", "thread", "final", "profiler", "objchecks", "intdefine", "strdefine",
|
||||
|
||||
"destroy",
|
||||
|
||||
|
||||
@@ -23,10 +23,6 @@ arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
||||
mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
|
||||
mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
|
||||
|
||||
@if not nimfix:
|
||||
cs:partial
|
||||
@end
|
||||
|
||||
path="$lib/deprecated/core"
|
||||
path="$lib/deprecated/pure"
|
||||
path="$lib/pure/collections"
|
||||
@@ -44,6 +40,11 @@ path="$lib/pure"
|
||||
|
||||
@if nimbabel:
|
||||
nimblepath="$home/.nimble/pkgs/"
|
||||
@if not windows:
|
||||
nimblepath="/opt/nimble/pkgs/"
|
||||
@else:
|
||||
# TODO:
|
||||
@end
|
||||
@end
|
||||
|
||||
@if release or quick:
|
||||
@@ -163,10 +164,5 @@ vcc.options.always = "/nologo"
|
||||
vcc.options.speed = "/O2 /arch:SSE2"
|
||||
vcc.options.size = "/O1"
|
||||
|
||||
# Configuration for the Digital Mars C/C++ compiler:
|
||||
@if windows:
|
||||
dmc.path = r"$nimrod\dist\dm\bin"
|
||||
@end
|
||||
|
||||
# Configuration for the Tiny C Compiler:
|
||||
tcc.options.always = "-w"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This is the config file for the documentation generator.
|
||||
# (c) 2012 Andreas Rumpf
|
||||
# (c) 2016 Andreas Rumpf
|
||||
# Feel free to edit the templates as you need. If you modify this file, it
|
||||
# might be worth updating the hardcoded values in packages/docutils/rstgen.nim
|
||||
|
||||
@@ -1235,10 +1235,46 @@ dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
|
||||
margin-bottom: -5px; }
|
||||
div.pragma {
|
||||
display: none;
|
||||
}
|
||||
span.pragmabegin {
|
||||
cursor: pointer;
|
||||
}
|
||||
span.pragmaend {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
function togglepragma(d) {
|
||||
if (d.style.display != 'inline')
|
||||
d.style.display = 'inline';
|
||||
else
|
||||
d.style.display = 'none';
|
||||
}
|
||||
|
||||
function main() {
|
||||
var elements = document.getElementsByClassName("pragmabegin");
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
var e = elements[i];
|
||||
e.onclick = function(event) {
|
||||
togglepragma(event.target.nextSibling);
|
||||
};
|
||||
}
|
||||
var elements = document.getElementsByClassName("pragmaend");
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
var e = elements[i];
|
||||
e.onclick = function(event) {
|
||||
togglepragma(event.target.previousSibling);
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<body onload="main()">
|
||||
<div class="document" id="documentId">
|
||||
<div class="container">
|
||||
<h1 class="title">$title</h1>
|
||||
|
||||
@@ -6,6 +6,7 @@ Advanced commands:
|
||||
//rst2html convert a reStructuredText file to HTML
|
||||
//rst2tex convert a reStructuredText file to TeX
|
||||
//jsondoc extract the documentation to a json file
|
||||
//jsondoc2 extract documentation to a json file (uses doc2)
|
||||
//buildIndex build an index for the whole documentation
|
||||
//run run the project (with Tiny C backend; buggy!)
|
||||
//genDepend generate a DOT file containing the
|
||||
|
||||
@@ -33,7 +33,7 @@ contains:
|
||||
of nnkIdent:
|
||||
ident: NimIdent ## the identifier
|
||||
of nnkSym:
|
||||
symbol: NimSymbol ## the symbol (after symbol lookup phase)
|
||||
symbol: NimSym ## the symbol (after symbol lookup phase)
|
||||
else:
|
||||
sons: seq[NimNode] ## the node's sons (or children)
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ interface <manual.html#foreign-function-interface>`_ mainly through the
|
||||
`importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
|
||||
*generic* way of making backend symbols available in Nim and is available
|
||||
in all the target backends (JavaScript too). The C++ or Objective-C backends
|
||||
have their respective `ImportCpp <nimc.html#importcpp-pragma>`_ and
|
||||
`ImportObjC <nimc.html#importobjc-pragma>`_ pragmas to call methods from
|
||||
have their respective `ImportCpp <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ pragmas to call methods from
|
||||
classes.
|
||||
|
||||
Whenever you use any of these pragmas you need to integrate native code into
|
||||
@@ -420,7 +420,7 @@ function directly will be able to use it since Nim's garbage collector has
|
||||
not had a chance to run *yet*. This gives you enough time to make a copy for
|
||||
the C side of the program, as calling any further Nim procs *might* trigger
|
||||
garbage collection making the previously returned string garbage. Or maybe you
|
||||
are `triggering yourself the collection <gc.html>`_.
|
||||
are `yourself triggering the collection <gc.html>`_.
|
||||
|
||||
|
||||
Custom data types
|
||||
|
||||
@@ -11,7 +11,9 @@ Arguments:
|
||||
arguments are passed to the program being run (if --run option is selected)
|
||||
Options:
|
||||
-p, --path:PATH add path to search paths
|
||||
-d, --define:SYMBOL define a conditional symbol
|
||||
-d, --define:SYMBOL(:VAL)
|
||||
define a conditional symbol
|
||||
(Optionally: Define the value for that symbol)
|
||||
-u, --undef:SYMBOL undefine a conditional symbol
|
||||
-f, --forceBuild force rebuilding of all modules
|
||||
--stackTrace:on|off turn stack tracing on|off
|
||||
|
||||
@@ -23,6 +23,10 @@ just like an ordinary procedure call with named or positional arguments. The
|
||||
available parameters depend on the invoked filter. Before version 0.12.0 of
|
||||
the language ``#!`` was used instead of ``#?``.
|
||||
|
||||
**Hint:** With ``--hint[codeBegin]:on```or ``--verbosity:2``
|
||||
(or higher) Nim lists the processed code after each filter
|
||||
application.
|
||||
|
||||
|
||||
Pipe operator
|
||||
=============
|
||||
@@ -41,9 +45,6 @@ Filters can be combined with the ``|`` pipe operator::
|
||||
Available filters
|
||||
=================
|
||||
|
||||
**Hint:** With ``--verbosity:2`` (or higher) Nim lists the processed code
|
||||
after each filter application.
|
||||
|
||||
Replace filter
|
||||
--------------
|
||||
|
||||
@@ -56,7 +56,7 @@ file as well). With this switch the GC supports the following operations:
|
||||
|
||||
.. code-block:: nim
|
||||
proc GC_setMaxPause*(MaxPauseInUs: int)
|
||||
proc GC_step*(us: int, strongAdvice = false)
|
||||
proc GC_step*(us: int, strongAdvice = false, stackSize = -1)
|
||||
|
||||
The unit of the parameters ``MaxPauseInUs`` and ``us`` is microseconds.
|
||||
|
||||
@@ -75,7 +75,13 @@ These two procs are the two modus operandi of the realtime GC:
|
||||
This allows the GC to perform some work for up to ``us`` time. This is
|
||||
useful to call in a main loop to ensure the GC can do its work. To
|
||||
bind all GC activity to a ``GC_step`` call, deactivate the GC with
|
||||
``GC_disable`` at program startup.
|
||||
``GC_disable`` at program startup. If ``strongAdvice`` is set to ``true``,
|
||||
GC will be forced to perform collection cycle. Otherwise, GC may decide not
|
||||
to do anything, if there is not much garbage to collect.
|
||||
You may also specify the current stack size via ``stackSize`` parameter.
|
||||
It can improve performance, when you know that there are no unique Nim
|
||||
references below certain point on the stack. Make sure the size you specify
|
||||
is greater than the potential worst case size.
|
||||
|
||||
These procs provide a "best effort" realtime guarantee; in particular the
|
||||
cycle collector is not aware of deadlines yet. Deactivate it to get more
|
||||
@@ -87,7 +87,7 @@ Collections and algorithms
|
||||
* `sequtils <sequtils.html>`_
|
||||
This module implements operations for the built-in seq type
|
||||
which were inspired by functional programming languages.
|
||||
|
||||
|
||||
|
||||
String handling
|
||||
---------------
|
||||
@@ -97,9 +97,16 @@ String handling
|
||||
case of a string, splitting a string into substrings, searching for
|
||||
substrings, replacing substrings.
|
||||
|
||||
* `strmisc <strmisc.html>`_
|
||||
This module contains uncommon string handling operations that do not
|
||||
fit with the commonly used operations in strutils.
|
||||
|
||||
* `parseutils <parseutils.html>`_
|
||||
This module contains helpers for parsing tokens, numbers, identifiers, etc.
|
||||
|
||||
* `strscans <strscans.html>`_
|
||||
This module contains a ``scanf`` macro for convenient parsing of mini languages.
|
||||
|
||||
* `strtabs <strtabs.html>`_
|
||||
The ``strtabs`` module implements an efficient hash table that is a mapping
|
||||
from strings to strings. Supports a case-sensitive, case-insensitive and
|
||||
@@ -199,6 +206,9 @@ Math libraries
|
||||
* `mersenne <mersenne.html>`_
|
||||
Mersenne twister random number generator.
|
||||
|
||||
* `random <random.html>`_
|
||||
Fast and tiny random number generator.
|
||||
|
||||
* `stats <stats.html>`_
|
||||
Statistical analysis
|
||||
|
||||
@@ -440,6 +450,10 @@ Regular expressions
|
||||
This module contains procedures and operators for handling regular
|
||||
expressions. The current implementation uses PCRE.
|
||||
|
||||
* `nre <nre.html>`_
|
||||
Another implementation of procedures for using regular expressions. Also uses
|
||||
PCRE.
|
||||
|
||||
|
||||
Database support
|
||||
----------------
|
||||
@@ -155,4 +155,4 @@ Exception hierarchy
|
||||
|
||||
The exception tree is defined in the `system <system.html>`_ module:
|
||||
|
||||
.. include:: exception_hierarchy_fragment.txt
|
||||
.. include:: ../exception_hierarchy_fragment.txt
|
||||
|
||||
@@ -16,11 +16,19 @@ spelled*:
|
||||
.. code-block::
|
||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||
|
||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
||||
Note that this pragma is somewhat of a misnomer: Other backends do provide
|
||||
the same feature under the same name. Also, if one is interfacing with C++
|
||||
the `ImportCpp pragma <nimc.html#importcpp-pragma>`_ and
|
||||
the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||
interfacing with Objective-C the `ImportObjC pragma
|
||||
<nimc.html#importobjc-pragma>`_ can be used.
|
||||
<manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
|
||||
|
||||
The string literal passed to ``importc`` can be a format string:
|
||||
|
||||
.. code-block:: Nim
|
||||
proc p(s: cstring) {.importc: "prefix$1".}
|
||||
|
||||
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||
is available and a literal dollar sign must be written as ``$$``.
|
||||
|
||||
|
||||
Exportc pragma
|
||||
@@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
|
||||
.. code-block:: Nim
|
||||
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
|
||||
|
||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
||||
Note that this pragma is somewhat of a misnomer: Other backends do provide
|
||||
the same feature under the same name.
|
||||
|
||||
The string literal passed to ``exportc`` can be a format string:
|
||||
|
||||
.. code-block:: Nim
|
||||
proc p(s: string) {.exportc: "prefix$1".} =
|
||||
echo s
|
||||
|
||||
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||
is available and a literal dollar sign must be written as ``$$``.
|
||||
|
||||
|
||||
|
||||
Extern pragma
|
||||
-------------
|
||||
@@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string:
|
||||
proc p(s: string) {.extern: "prefix$1".} =
|
||||
echo s
|
||||
|
||||
In the example the external name of ``p`` is set to ``prefixp``.
|
||||
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||
is available and a literal dollar sign must be written as ``$$``.
|
||||
|
||||
|
||||
|
||||
Bycopy pragma
|
||||
|
||||
@@ -232,16 +232,6 @@ type signatures of the required operations, but since type inference and
|
||||
default parameters are still applied in the provided block, it's also possible
|
||||
to encode usage protocols that do not reveal implementation details.
|
||||
|
||||
As a special rule providing further convenience when writing concepts, any
|
||||
type value appearing in a callable expression will be treated as a variable of
|
||||
the designated type for overload resolution purposes, unless the type value was
|
||||
passed in its explicit ``typedesc[T]`` form:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
OutputStream = concept s
|
||||
write(var s, string)
|
||||
|
||||
Much like generics, concepts are instantiated exactly
|
||||
once for each tested type and any static code included within them is also
|
||||
executed once.
|
||||
@@ -303,7 +293,7 @@ definition):
|
||||
var
|
||||
lastId = 0
|
||||
|
||||
template genId*: expr =
|
||||
template genId*: untyped =
|
||||
bind lastId
|
||||
inc(lastId)
|
||||
lastId
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user