Merge branch 'devel'
This commit is contained in:
commit
3892969af4
1019 changed files with 35409 additions and 74200 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -41,4 +41,4 @@ xcuserdata/
|
|||
/testresults.html
|
||||
/testresults.json
|
||||
testament.db
|
||||
/csources/
|
||||
/csources
|
||||
|
|
|
|||
35
.travis.yml
Normal file
35
.travis.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
sudo: false
|
||||
language: c
|
||||
os:
|
||||
- linux
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcurl4-openssl-dev
|
||||
- libsdl1.2-dev
|
||||
- libgc-dev
|
||||
before_script:
|
||||
- set -e
|
||||
- wget http://flatassembler.net/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
|
||||
- sh build.sh
|
||||
- cd ..
|
||||
- sed -i -e 's,cc = gcc,cc = clang,' config/nim.cfg
|
||||
- export PATH=$(pwd)/bin:$(pwd)/fasm:$PATH
|
||||
script:
|
||||
- nim c koch
|
||||
- ./koch boot
|
||||
- ./koch boot -d:release
|
||||
- nim e install_nimble.nims
|
||||
- nimble update
|
||||
- nimble install zip
|
||||
- nimble install opengl
|
||||
- nimble install sdl1
|
||||
- nimble install jester
|
||||
- nimble install niminst
|
||||
- nim c --taintMode:on tests/testament/tester
|
||||
- tests/testament/tester --pedantic all
|
||||
- ./koch csource
|
||||
- ./koch xz
|
||||
36
appveyor.yml
Normal file
36
appveyor.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
clone_depth: 5
|
||||
|
||||
artifacts:
|
||||
- path: bin\nim.exe
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
before_build:
|
||||
- git log -1
|
||||
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S zlib-devel"
|
||||
- appveyor DownloadFile http://nim-lang.org/download/dlls.zip
|
||||
- 7z e dlls.zip -odlls
|
||||
- del dlls\libcurl.dll
|
||||
- appveyor DownloadFile http://flatassembler.net/fasmw17139.zip
|
||||
- 7z e fasmw17139.zip -obin fasm.exe
|
||||
|
||||
build_script:
|
||||
- SET PATH=C:\msys64\mingw64\bin;dlls;bin;%PATH%
|
||||
- gcc -v
|
||||
- git clone -q --depth 1 https://github.com/nim-lang/csources
|
||||
- cd csources
|
||||
- build64.bat
|
||||
- cd ..
|
||||
- nim c koch
|
||||
- koch boot
|
||||
- koch boot -d:release
|
||||
|
||||
before_test:
|
||||
- nim e install_nimble.nims
|
||||
- nimble update
|
||||
- nimble install zip
|
||||
|
||||
test_script:
|
||||
- nim c --taintMode:on tests/testament/tester
|
||||
- tests\testament\tester --pedantic all
|
||||
|
|
@ -1 +1 @@
|
|||
This file keeps several tools from deleting this subdirectory.
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
|
|
|
|||
22
bootstrap.sh
Executable file
22
bootstrap.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [ ! -e csources/.git ]; then
|
||||
git clone --depth 1 git://github.com/nim-lang/csources.git csources
|
||||
fi
|
||||
|
||||
cd "csources"
|
||||
sh build.sh
|
||||
cd ".."
|
||||
|
||||
./bin/nim c koch
|
||||
./koch boot -d:release
|
||||
./koch geninstall
|
||||
|
||||
set +x
|
||||
|
||||
echo
|
||||
echo 'Install Nim using "./install.sh <dir>" or "sudo ./install.sh <dir>".'
|
||||
|
||||
exit 0
|
||||
19
build.sh
19
build.sh
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [ ! -d "csources" ]; then
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
fi
|
||||
|
||||
cd "csources"
|
||||
sh build.sh
|
||||
cd ".."
|
||||
|
||||
./bin/nim c koch
|
||||
./koch boot -d:release
|
||||
|
||||
cp -f install.sh.template install.sh
|
||||
chmod +x install.sh
|
||||
|
||||
exit 0
|
||||
|
|
@ -1 +1 @@
|
|||
This file keeps several tools from deleting this subdirectory.
|
||||
This file keeps several tools from deleting this subdirectory.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[Package]
|
||||
name = "compiler"
|
||||
version = "0.10.3"
|
||||
version = "0.11.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.10.3"
|
||||
Requires: "nim >= 0.11.3"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import
|
||||
ast, astalgo, types, trees, intsets, msgs
|
||||
|
||||
|
||||
type
|
||||
TAnalysisResult* = enum
|
||||
arNo, arMaybe, arYes
|
||||
|
|
@ -21,42 +21,42 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
|
|||
proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = isPartOfAux(n.sons[i], b, marker)
|
||||
if result == arYes: return
|
||||
of nkRecCase:
|
||||
assert(n.sons[0].kind == nkSym)
|
||||
result = isPartOfAux(n.sons[0], b, marker)
|
||||
if result == arYes: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkOfBranch, nkElse:
|
||||
of nkOfBranch, nkElse:
|
||||
result = isPartOfAux(lastSon(n.sons[i]), b, marker)
|
||||
if result == arYes: return
|
||||
else: internalError("isPartOfAux(record case branch)")
|
||||
of nkSym:
|
||||
result = isPartOfAux(n.sym.typ, b, marker)
|
||||
else: internalError(n.info, "isPartOfAux()")
|
||||
|
||||
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
|
||||
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
if a == nil or b == nil: return
|
||||
if containsOrIncl(marker, a.id): return
|
||||
if a == nil or b == nil: return
|
||||
if containsOrIncl(marker, a.id): return
|
||||
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
|
||||
case a.kind
|
||||
of tyObject:
|
||||
of tyObject:
|
||||
result = isPartOfAux(a.sons[0], b, marker)
|
||||
if result == arNo: result = isPartOfAux(a.n, b, marker)
|
||||
of tyGenericInst, tyDistinct:
|
||||
result = isPartOfAux(lastSon(a), b, marker)
|
||||
of tyArray, tyArrayConstr, tySet, tyTuple:
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
of tyArray, tyArrayConstr, tySet, tyTuple:
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
result = isPartOfAux(a.sons[i], b, marker)
|
||||
if result == arYes: return
|
||||
if result == arYes: return
|
||||
else: discard
|
||||
|
||||
proc isPartOf(a, b: PType): TAnalysisResult =
|
||||
proc isPartOf(a, b: PType): TAnalysisResult =
|
||||
## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
|
||||
var marker = initIntSet()
|
||||
# watch out: parameters reversed because I'm too lazy to change the code...
|
||||
|
|
@ -70,14 +70,14 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
## type. Since however type analysis is more expensive, we perform it only
|
||||
## if necessary.
|
||||
##
|
||||
## cases:
|
||||
## cases:
|
||||
##
|
||||
## YES-cases:
|
||||
## x <| x # for general trees
|
||||
## x[] <| x
|
||||
## x[i] <| x
|
||||
## x.f <| x
|
||||
##
|
||||
##
|
||||
## NO-cases:
|
||||
## x !<| y # depending on type and symbol kind
|
||||
## x[constA] !<| x[constB]
|
||||
|
|
@ -88,16 +88,16 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
##
|
||||
## x[] ?<| y[] iff compatible type
|
||||
##
|
||||
##
|
||||
##
|
||||
## x[] ?<| y depending on type
|
||||
##
|
||||
##
|
||||
if a.kind == b.kind:
|
||||
case a.kind
|
||||
of nkSym:
|
||||
const varKinds = {skVar, skTemp, skProc}
|
||||
# same symbol: aliasing:
|
||||
if a.sym.id == b.sym.id: result = arYes
|
||||
elif a.sym.kind in varKinds or b.sym.kind in varKinds:
|
||||
elif a.sym.kind in varKinds or b.sym.kind in varKinds:
|
||||
# actually, a param could alias a var but we know that cannot happen
|
||||
# here. XXX make this more generic
|
||||
result = arNo
|
||||
|
|
@ -110,11 +110,11 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
if len(a) >= 2 and len(b) >= 2:
|
||||
# array accesses:
|
||||
if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
|
||||
# we know it's the same array and we have 2 constant indexes;
|
||||
# if they are
|
||||
# we know it's the same array and we have 2 constant indexes;
|
||||
# if they are
|
||||
var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
|
||||
var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
|
||||
|
||||
|
||||
if sameValue(x, y): result = arYes
|
||||
else: result = arNo
|
||||
# else: maybe and no are accurate
|
||||
|
|
@ -122,7 +122,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
# pointer derefs:
|
||||
if result != arYes:
|
||||
if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
|
||||
|
||||
|
||||
of nkDotExpr:
|
||||
result = isPartOf(a[0], b[0])
|
||||
if result != arNo:
|
||||
|
|
@ -135,7 +135,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
# weaken because of indirection:
|
||||
if result != arYes:
|
||||
if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
|
||||
|
||||
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = isPartOf(a[1], b[1])
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
|
|
@ -144,26 +144,26 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
# Calls return a new location, so a default of ``arNo`` is fine.
|
||||
else:
|
||||
# go down recursively; this is quite demanding:
|
||||
const
|
||||
const
|
||||
Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
|
||||
nkCheckedFieldExpr}
|
||||
nkCheckedFieldExpr, nkHiddenAddr}
|
||||
Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv}
|
||||
DerefKinds = {nkHiddenDeref, nkDerefExpr}
|
||||
case b.kind
|
||||
of Ix0Kinds:
|
||||
# a* !<| b.f iff a* !<| b
|
||||
result = isPartOf(a, b[0])
|
||||
|
||||
|
||||
of DerefKinds:
|
||||
# a* !<| b[] iff
|
||||
# a* !<| b[] iff
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a, b[0])
|
||||
if result == arNo: result = arMaybe
|
||||
|
||||
|
||||
of Ix1Kinds:
|
||||
# a* !<| T(b) iff a* !<| b
|
||||
result = isPartOf(a, b[1])
|
||||
|
||||
|
||||
of nkSym:
|
||||
# b is an atom, so we have to check a:
|
||||
case a.kind
|
||||
|
|
@ -172,7 +172,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
|
|||
result = isPartOf(a[0], b)
|
||||
of Ix1Kinds:
|
||||
result = isPartOf(a[1], b)
|
||||
|
||||
|
||||
of DerefKinds:
|
||||
if isPartOf(a.typ, b.typ) != arNo:
|
||||
result = isPartOf(a[0], b)
|
||||
|
|
|
|||
191
compiler/ast.nim
191
compiler/ast.nim
|
|
@ -10,7 +10,7 @@
|
|||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
msgs, hashes, nversion, options, strutils, securehash, ropes, idents, lists,
|
||||
intsets, idgen
|
||||
|
||||
type
|
||||
|
|
@ -291,12 +291,13 @@ const
|
|||
sfNoForward* = sfRegister
|
||||
# forward declarations are not required (per module)
|
||||
|
||||
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
||||
# require RC ops
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||
sfGoto* = sfOverriden # var is used for 'goto' code generation
|
||||
sfWrittenTo* = sfBorrow # param is assigned to
|
||||
sfEscapes* = sfProcvar # param escapes
|
||||
sfBase* = sfDiscriminant
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
|
|
@ -423,6 +424,7 @@ type
|
|||
# but unfortunately it has measurable impact for compilation
|
||||
# efficiency
|
||||
nfTransf, # node has been transformed
|
||||
nfNoRewrite # node should not be transformed anymore
|
||||
nfSem # node has been checked for semantics
|
||||
nfLL # node has gone through lambda lifting
|
||||
nfDotField # the call can use a dot operator
|
||||
|
|
@ -475,6 +477,8 @@ type
|
|||
# wildcard type.
|
||||
tfHasAsgn # type has overloaded assignment operator
|
||||
tfBorrowDot # distinct type borrows '.'
|
||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||
# implicitly '.compiletime'
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
|
|
@ -521,6 +525,12 @@ const
|
|||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
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
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
|
|
@ -529,40 +539,52 @@ const
|
|||
type
|
||||
TMagic* = enum # symbols that require compiler magic:
|
||||
mNone,
|
||||
mDefined, mDefinedInScope, mCompiles,
|
||||
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
|
||||
mUnaryLt, mInc, mDec, mOrd,
|
||||
mNew, mNewFinalize, mNewSeq,
|
||||
mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
|
||||
mXLenStr, mXLenSeq,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
mGCref, mGCunref,
|
||||
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mSucc, mPred,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI,
|
||||
mSucc, mPred,
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI,
|
||||
mMinI, mMaxI,
|
||||
mMinF64, mMaxF64,
|
||||
mAddU, mSubU, mMulU, mDivU, mModU,
|
||||
mEqI, mLeI, mLtI,
|
||||
mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU,
|
||||
mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum,
|
||||
mEqCh, mLeCh, mLtCh,
|
||||
mEqB, mLeB, mLtB,
|
||||
mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mEqCString,
|
||||
mXor, mEqProc,
|
||||
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
|
||||
mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64,
|
||||
mZe32ToI64, mZeIToI64,
|
||||
mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat,
|
||||
mToInt, mToBiggestInt,
|
||||
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
|
||||
mStrToStr, mEnumToStr,
|
||||
mAnd, mOr,
|
||||
mEqStr, mLeStr, mLtStr,
|
||||
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet,
|
||||
mConStrStr, mSlice,
|
||||
mDotDot, # this one is only necessary to give nice compile time warnings
|
||||
mFields, mFieldPairs, mOmpParFor,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
|
||||
mInRange, mInSet, mRepr, mExit,
|
||||
mSetLengthStr, mSetLengthSeq,
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
|
|
@ -584,42 +606,53 @@ type
|
|||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||
mNBindSym, mLocals, mNCallSite,
|
||||
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo, mNGenSym
|
||||
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
|
||||
mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo, mNGenSym,
|
||||
mNimvm
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
|
||||
mArrGet, mArrPut, mAsgn,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI,
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI,
|
||||
mMinI, mMaxI,
|
||||
mMinF64, mMaxF64,
|
||||
mAddU, mSubU, mMulU, mDivU, mModU,
|
||||
mEqI, mLeI, mLtI,
|
||||
mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU,
|
||||
mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum,
|
||||
mEqCh, mLeCh, mLtCh,
|
||||
mEqB, mLeB, mLtB,
|
||||
mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor,
|
||||
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
|
||||
mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64,
|
||||
mZe32ToI64, mZeIToI64,
|
||||
mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat,
|
||||
mToInt, mToBiggestInt,
|
||||
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
|
||||
mStrToStr, mEnumToStr,
|
||||
mAnd, mOr,
|
||||
mEqStr, mLeStr, mLtStr,
|
||||
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet,
|
||||
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr,
|
||||
mCopyStr, mCopyStrLast}
|
||||
# magics that require special semantic checking and
|
||||
# thus cannot be overloaded (also documented in the spec!):
|
||||
SpecialSemMagics* = {
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
|
||||
type
|
||||
PNode* = ref TNode
|
||||
|
|
@ -679,6 +712,7 @@ type
|
|||
lfSingleUse # no location yet and will only be used once
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStatic, # in a static section
|
||||
OnStack, # location is on hardware stack
|
||||
OnHeap # location is on heap or global
|
||||
# (reference counting needed)
|
||||
|
|
@ -704,6 +738,8 @@ type
|
|||
name*: Rope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
CompilesId* = int ## id that is used for the caching logic within
|
||||
## ``system.compiles``. See the seminst module.
|
||||
TInstantiation* = object
|
||||
sym*: PSym
|
||||
concreteTypes*: seq[PType]
|
||||
|
|
@ -711,6 +747,7 @@ type
|
|||
# needed in caas mode for purging the cache
|
||||
# XXX: it's possible to switch to a
|
||||
# simple ref count here
|
||||
compilesId*: CompilesId
|
||||
|
||||
PInstantiation* = ref TInstantiation
|
||||
|
||||
|
|
@ -747,6 +784,7 @@ type
|
|||
tab*: TStrTable # interface table for modules
|
||||
of skLet, skVar, skField, skForVar:
|
||||
guard*: PSym
|
||||
bitsize*: int
|
||||
else: nil
|
||||
magic*: TMagic
|
||||
typ*: PType
|
||||
|
|
@ -842,7 +880,7 @@ type
|
|||
data*: TIdNodePairSeq
|
||||
|
||||
TNodePair* = object
|
||||
h*: THash # because it is expensive to compute!
|
||||
h*: Hash # because it is expensive to compute!
|
||||
key*: PNode
|
||||
val*: int
|
||||
|
||||
|
|
@ -947,6 +985,9 @@ proc add*(father, son: PNode) =
|
|||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
template `-|`*(b, s: expr): expr =
|
||||
(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 =
|
||||
|
|
@ -1000,7 +1041,8 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
|||
result.id = getID()
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
#if result.id == 93289:
|
||||
# writeStacktrace()
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
||||
var emptyNode* = newNode(nkEmpty)
|
||||
|
|
@ -1198,23 +1240,11 @@ proc newSons*(father: PType, length: int) =
|
|||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon*(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
proc sonsLen*(n: PType): int = n.sons.len
|
||||
proc len*(n: PType): int = n.sons.len
|
||||
proc sonsLen*(n: PNode): int = n.sons.len
|
||||
proc lastSon*(n: PNode): PNode = n.sons[^1]
|
||||
proc lastSon*(n: PType): PType = n.sons[^1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
|
|
@ -1356,8 +1386,11 @@ proc propagateToOwner*(owner, elem: PType) =
|
|||
o2.flags.incl tfHasAsgn
|
||||
owner.flags.incl tfHasAsgn
|
||||
|
||||
if tfTriggersCompileTime in elem.flags:
|
||||
owner.flags.incl tfTriggersCompileTime
|
||||
|
||||
if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
|
||||
tyGenericInvocation}:
|
||||
tyGenericInvocation, tyPtr}:
|
||||
let elemB = elem.skipTypes({tyGenericInst})
|
||||
if elemB.isGCedMem or tfHasGCedMem in elemB.flags:
|
||||
# for simplicity, we propagate this flag even to generics. We then
|
||||
|
|
@ -1496,6 +1529,9 @@ proc getFloat*(a: PNode): BiggestFloat =
|
|||
proc getStr*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkNilLit:
|
||||
# let's hope this fixes more problems than it creates:
|
||||
result = nil
|
||||
else:
|
||||
internalError(a.info, "getStr")
|
||||
result = ""
|
||||
|
|
@ -1553,6 +1589,14 @@ proc makeStmtList*(n: PNode): PNode =
|
|||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add n
|
||||
|
||||
proc skipStmtList*(n: PNode): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
for i in 0 .. n.len-2:
|
||||
if n[i].kind notin {nkEmpty, nkCommentStmt}: return n
|
||||
result = n.lastSon
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc createMagic*(name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
|
||||
result.magic = m
|
||||
|
|
@ -1560,3 +1604,10 @@ proc createMagic*(name: string, m: TMagic): PSym =
|
|||
let
|
||||
opNot* = createMagic("not", mNot)
|
||||
opContains* = createMagic("contains", mInSet)
|
||||
|
||||
when false:
|
||||
proc containsNil*(n: PNode): bool =
|
||||
# only for debugging
|
||||
if n.isNil: return true
|
||||
for i in 0 ..< n.safeLen:
|
||||
if n[i].containsNil: return true
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
import
|
||||
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
|
||||
|
||||
proc hashNode*(p: RootRef): THash
|
||||
proc hashNode*(p: RootRef): Hash
|
||||
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
|
||||
# Convert a tree into its YAML representation; this is used by the
|
||||
# YAML code generator and it is invaluable for debugging purposes.
|
||||
|
|
@ -49,7 +49,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym
|
|||
|
||||
type
|
||||
TTabIter*{.final.} = object # consider all fields here private
|
||||
h*: THash # current hash
|
||||
h*: Hash # current hash
|
||||
|
||||
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
||||
|
|
@ -65,7 +65,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
|
|||
|
||||
type
|
||||
TIdentIter*{.final.} = object # iterator over all syms with same identifier
|
||||
h*: THash # current hash
|
||||
h*: Hash # current hash
|
||||
name*: PIdent
|
||||
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
|
|||
proc lookupInRecord*(n: PNode, field: PIdent): PSym
|
||||
proc getModule*(s: PSym): PSym
|
||||
proc mustRehash*(length, counter: int): bool
|
||||
proc nextTry*(h, maxHash: THash): THash {.inline.}
|
||||
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
|
||||
|
||||
# ------------- table[int, int] ---------------------------------------------
|
||||
const
|
||||
|
|
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
|||
else: internalError(list.info, "getSymFromList")
|
||||
result = nil
|
||||
|
||||
proc hashNode(p: RootRef): THash =
|
||||
proc hashNode(p: RootRef): Hash =
|
||||
result = hash(cast[pointer](p))
|
||||
|
||||
proc mustRehash(length, counter: int): bool =
|
||||
|
|
@ -452,7 +452,7 @@ proc debug(n: PSym) =
|
|||
elif n.kind == skUnknown:
|
||||
msgWriteln("skUnknown")
|
||||
else:
|
||||
#writeln(stdout, $symToYaml(n, 0, 1))
|
||||
#writeLine(stdout, $symToYaml(n, 0, 1))
|
||||
msgWriteln("$1_$2: $3, $4, $5, $6" % [
|
||||
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
|
||||
$lineInfoToStr(n.info), $n.kind])
|
||||
|
|
@ -466,7 +466,7 @@ proc debug(n: PNode) =
|
|||
const
|
||||
EmptySeq = @[]
|
||||
|
||||
proc nextTry(h, maxHash: THash): THash =
|
||||
proc nextTry(h, maxHash: Hash): Hash =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
# For any initial h in range(maxHash), repeating that maxHash times
|
||||
# generates each int in range(maxHash) exactly once (see any text on
|
||||
|
|
@ -474,7 +474,7 @@ proc nextTry(h, maxHash: THash): THash =
|
|||
|
||||
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
|
||||
# returns true whether n is in t
|
||||
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
|
||||
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
if t.data[h] == obj:
|
||||
return true
|
||||
|
|
@ -482,7 +482,7 @@ proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
|
|||
result = false
|
||||
|
||||
proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
|
||||
var h: THash = hashNode(obj) and high(data)
|
||||
var h: Hash = hashNode(obj) and high(data)
|
||||
while data[h] != nil:
|
||||
assert(data[h] != obj)
|
||||
h = nextTry(h, high(data))
|
||||
|
|
@ -503,7 +503,7 @@ proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
|
|||
|
||||
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
|
||||
# returns true if obj is already in the string table:
|
||||
var h: THash = hashNode(obj) and high(t.data)
|
||||
var h: Hash = hashNode(obj) and high(t.data)
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
|
|
@ -520,7 +520,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
|
|||
result = false
|
||||
|
||||
proc tableRawGet(t: TTable, key: RootRef): int =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key == key:
|
||||
return h
|
||||
|
|
@ -529,7 +529,7 @@ proc tableRawGet(t: TTable, key: RootRef): int =
|
|||
|
||||
proc tableSearch(t: TTable, key, closure: RootRef,
|
||||
comparator: TCmpProc): RootRef =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key == key:
|
||||
if comparator(t.data[h].val, closure):
|
||||
|
|
@ -544,7 +544,7 @@ proc tableGet(t: TTable, key: RootRef): RootRef =
|
|||
else: result = nil
|
||||
|
||||
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
|
||||
var h: THash = hashNode(key) and high(data)
|
||||
var h: Hash = hashNode(key) and high(data)
|
||||
while data[h].key != nil:
|
||||
assert(data[h].key != key)
|
||||
h = nextTry(h, high(data))
|
||||
|
|
@ -569,7 +569,7 @@ proc tablePut(t: var TTable, key, val: RootRef) =
|
|||
inc(t.counter)
|
||||
|
||||
proc strTableContains(t: TStrTable, n: PSym): bool =
|
||||
var h: THash = n.name.h and high(t.data) # start with real hash value
|
||||
var h: Hash = n.name.h and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
if (t.data[h] == n):
|
||||
return true
|
||||
|
|
@ -577,7 +577,7 @@ proc strTableContains(t: TStrTable, n: PSym): bool =
|
|||
result = false
|
||||
|
||||
proc strTableRawInsert(data: var TSymSeq, n: PSym) =
|
||||
var h: THash = n.name.h and high(data)
|
||||
var h: Hash = n.name.h and high(data)
|
||||
if sfImmediate notin n.flags:
|
||||
# fast path:
|
||||
while data[h] != nil:
|
||||
|
|
@ -606,7 +606,7 @@ proc strTableRawInsert(data: var TSymSeq, n: PSym) =
|
|||
|
||||
proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
|
||||
assert prevSym.name.h == newSym.name.h
|
||||
var h: THash = prevSym.name.h and high(data)
|
||||
var h: Hash = prevSym.name.h and high(data)
|
||||
while data[h] != nil:
|
||||
if data[h] == prevSym:
|
||||
data[h] = newSym
|
||||
|
|
@ -640,7 +640,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
|||
# It is essential that `n` is written nevertheless!
|
||||
# This way the newest redefinition is picked by the semantic analyses!
|
||||
assert n.name != nil
|
||||
var h: THash = n.name.h and high(t.data)
|
||||
var h: Hash = n.name.h and high(t.data)
|
||||
var replaceSlot = -1
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
|
|
@ -666,7 +666,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
|||
result = false
|
||||
|
||||
proc strTableGet(t: TStrTable, name: PIdent): PSym =
|
||||
var h: THash = name.h and high(t.data)
|
||||
var h: Hash = name.h and high(t.data)
|
||||
while true:
|
||||
result = t.data[h]
|
||||
if result == nil: break
|
||||
|
|
@ -694,7 +694,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
|||
|
||||
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
excluding: IntSet): PSym =
|
||||
var h: THash = ti.h and high(tab.data)
|
||||
var h: Hash = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
|
|
@ -743,7 +743,7 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
|
|||
result = false
|
||||
|
||||
proc idTableRawGet(t: TIdTable, key: int): int =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key.id == key:
|
||||
|
|
@ -772,7 +772,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
|
|||
yield (t.data[i].key.id, t.data[i].val)
|
||||
|
||||
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key.id and high(data)
|
||||
while data[h].key != nil:
|
||||
assert(data[h].key.id != key.id)
|
||||
|
|
@ -805,7 +805,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
|
|||
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
|
||||
|
||||
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key.id and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key.id == key.id:
|
||||
|
|
@ -824,7 +824,7 @@ proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
|
|||
result = idNodeTableGet(t, key)
|
||||
|
||||
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key.id and high(data)
|
||||
while data[h].key != nil:
|
||||
assert(data[h].key.id != key.id)
|
||||
|
|
@ -863,7 +863,7 @@ proc initIITable(x: var TIITable) =
|
|||
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
|
||||
|
||||
proc iiTableRawGet(t: TIITable, key: int): int =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key and high(t.data) # start with real hash value
|
||||
while t.data[h].key != InvalidKey:
|
||||
if t.data[h].key == key: return h
|
||||
|
|
@ -876,7 +876,7 @@ proc iiTableGet(t: TIITable, key: int): int =
|
|||
else: result = InvalidKey
|
||||
|
||||
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
|
||||
var h: THash
|
||||
var h: Hash
|
||||
h = key and high(data)
|
||||
while data[h].key != InvalidKey:
|
||||
assert(data[h].key != key)
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@
|
|||
# this unit handles Nim sets; it implements bit sets
|
||||
# the code here should be reused in the Nim standard library
|
||||
|
||||
type
|
||||
type
|
||||
TBitSet* = seq[int8] # we use byte here to avoid issues with
|
||||
# cross-compiling; uint would be more efficient
|
||||
# however
|
||||
|
||||
const
|
||||
const
|
||||
ElemSize* = sizeof(int8) * 8
|
||||
|
||||
proc bitSetInit*(b: var TBitSet, length: int)
|
||||
|
|
@ -30,42 +30,42 @@ proc bitSetEquals*(x, y: TBitSet): bool
|
|||
proc bitSetContains*(x, y: TBitSet): bool
|
||||
# implementation
|
||||
|
||||
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
|
||||
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
|
||||
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
|
||||
toU8(0)
|
||||
|
||||
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
|
||||
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
|
||||
assert(elem >= 0)
|
||||
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
|
||||
toU8(int(1 shl (elem mod ElemSize)))
|
||||
|
||||
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
|
||||
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
|
||||
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
|
||||
not toU8(int(1 shl (elem mod ElemSize)))
|
||||
|
||||
proc bitSetInit(b: var TBitSet, length: int) =
|
||||
proc bitSetInit(b: var TBitSet, length: int) =
|
||||
newSeq(b, length)
|
||||
|
||||
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
|
||||
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] or y[i]
|
||||
|
||||
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
|
||||
|
||||
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] and not y[i]
|
||||
|
||||
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
|
||||
|
||||
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] xor y[i]
|
||||
|
||||
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
|
||||
|
||||
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
|
||||
for i in countup(0, high(x)): x[i] = x[i] and y[i]
|
||||
|
||||
proc bitSetEquals(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if x[i] != y[i]:
|
||||
|
||||
proc bitSetEquals(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if x[i] != y[i]:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc bitSetContains(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if (x[i] and not y[i]) != int8(0):
|
||||
proc bitSetContains(x, y: TBitSet): bool =
|
||||
for i in countup(0, high(x)):
|
||||
if (x[i] and not y[i]) != int8(0):
|
||||
return false
|
||||
result = true
|
||||
|
|
|
|||
|
|
@ -30,39 +30,39 @@ type
|
|||
#
|
||||
# This is a good compromise between correctness and brevity. ;-)
|
||||
|
||||
const
|
||||
const
|
||||
cb64 = [
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||
"O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
|
||||
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
|
||||
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"_A", "_B"]
|
||||
|
||||
proc toBase64a(s: cstring, len: int): string =
|
||||
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||
## `newline` is added.
|
||||
result = newStringOfCap(((len + 2) div 3) * 4)
|
||||
var i = 0
|
||||
while i < s.len - 2:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
let c = ord(s[i+2])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
|
||||
result.add cb64[c and 0x3F]
|
||||
inc(i, 3)
|
||||
if i < s.len-1:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2)]
|
||||
elif i < s.len:
|
||||
let a = ord(s[i])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[(a and 3) shl 4]
|
||||
"_A", "_B"]
|
||||
|
||||
proc toBase64a(s: cstring, len: int): string =
|
||||
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||
## `newline` is added.
|
||||
result = newStringOfCap(((len + 2) div 3) * 4)
|
||||
var i = 0
|
||||
while i < s.len - 2:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
let c = ord(s[i+2])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
|
||||
result.add cb64[c and 0x3F]
|
||||
inc(i, 3)
|
||||
if i < s.len-1:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2)]
|
||||
elif i < s.len:
|
||||
let a = ord(s[i])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[(a and 3) shl 4]
|
||||
|
||||
proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ proc hashSym(c: var MD5Context, s: PSym) =
|
|||
c &= ":anon"
|
||||
else:
|
||||
var it = s.owner
|
||||
while it != nil:
|
||||
while it != nil:
|
||||
hashSym(c, it)
|
||||
c &= "."
|
||||
it = s.owner
|
||||
|
|
@ -106,18 +106,18 @@ proc hashTree(c: var MD5Context, n: PNode) =
|
|||
|
||||
proc hashType(c: var MD5Context, t: PType) =
|
||||
# modelled after 'typeToString'
|
||||
if t == nil:
|
||||
if t == nil:
|
||||
c &= "\254"
|
||||
return
|
||||
|
||||
var k = t.kind
|
||||
md5Update(c, cast[cstring](addr(k)), 1)
|
||||
|
||||
|
||||
if t.sym != nil and sfAnon notin t.sym.flags:
|
||||
# t.n for literals, but not for e.g. objects!
|
||||
if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
|
||||
c.hashSym(t.sym)
|
||||
|
||||
|
||||
case t.kind
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
|
||||
|
|
@ -135,10 +135,10 @@ proc hashType(c: var MD5Context, t: PType) =
|
|||
of tyArrayConstr:
|
||||
c.hashTree(t.sons[0].n)
|
||||
c.hashType(t.sons[1])
|
||||
of tyTuple:
|
||||
of tyTuple:
|
||||
if t.n != nil:
|
||||
assert(sonsLen(t.n) == sonsLen(t))
|
||||
for i in countup(0, sonsLen(t.n) - 1):
|
||||
for i in countup(0, sonsLen(t.n) - 1):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
c &= t.n.sons[i].sym.name.s
|
||||
c &= ":"
|
||||
|
|
@ -184,18 +184,18 @@ proc pushSym(w: PRodWriter, s: PSym) =
|
|||
if iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
w.sstack.add(s)
|
||||
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("()")
|
||||
return
|
||||
result.add('(')
|
||||
encodeVInt(ord(n.kind), result)
|
||||
encodeVInt(ord(n.kind), result)
|
||||
# we do not write comments for now
|
||||
# Line information takes easily 20% or more of the filesize! Therefore we
|
||||
# omit line information if it is the same as the father's line information:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
|
|
@ -211,7 +211,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
var f = n.flags * PersistentNodeFlags
|
||||
if f != {}:
|
||||
if f != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](f), result)
|
||||
if n.typ != nil:
|
||||
|
|
@ -219,16 +219,16 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
encodeVInt(n.typ.id, result)
|
||||
pushType(w, n.typ)
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
of nkCharLit..nkInt64Lit:
|
||||
if n.intVal != 0:
|
||||
result.add('!')
|
||||
encodeVBiggestInt(n.intVal, result)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
result.add('!')
|
||||
encodeStr($n.floatVal, result)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if n.strVal != "":
|
||||
if n.strVal != "":
|
||||
result.add('!')
|
||||
encodeStr(n.strVal, result)
|
||||
of nkIdent:
|
||||
|
|
@ -239,7 +239,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
|
|
@ -268,9 +268,9 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
|||
setLen(result, oldLen)
|
||||
else:
|
||||
add(result, '>')
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("[]")
|
||||
return
|
||||
|
|
@ -282,38 +282,38 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
|||
encodeVInt(ord(t.kind), result)
|
||||
add(result, '+')
|
||||
encodeVInt(t.id, result)
|
||||
if t.n != nil:
|
||||
if t.n != nil:
|
||||
encodeNode(w, unknownLineInfo(), t.n, result)
|
||||
if t.flags != {}:
|
||||
if t.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](t.flags), result)
|
||||
if t.callConv != low(t.callConv):
|
||||
if t.callConv != low(t.callConv):
|
||||
add(result, '?')
|
||||
encodeVInt(ord(t.callConv), result)
|
||||
if t.owner != nil:
|
||||
if t.owner != nil:
|
||||
add(result, '*')
|
||||
encodeVInt(t.owner.id, result)
|
||||
pushSym(w, t.owner)
|
||||
if t.sym != nil:
|
||||
if t.sym != nil:
|
||||
add(result, '&')
|
||||
encodeVInt(t.sym.id, result)
|
||||
pushSym(w, t.sym)
|
||||
if t.size != - 1:
|
||||
if t.size != - 1:
|
||||
add(result, '/')
|
||||
encodeVBiggestInt(t.size, result)
|
||||
if t.align != 2:
|
||||
if t.align != 2:
|
||||
add(result, '=')
|
||||
encodeVInt(t.align, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
add(result, '^')
|
||||
else:
|
||||
add(result, '^')
|
||||
encodeVInt(t.sons[i].id, result)
|
||||
pushType(w, t.sons[i])
|
||||
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
|
|
@ -352,10 +352,10 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
if s.magic != mNone:
|
||||
result.add('@')
|
||||
encodeVInt(ord(s.magic), result)
|
||||
if s.options != w.options:
|
||||
if s.options != w.options:
|
||||
result.add('!')
|
||||
encodeVInt(cast[int32](s.options), result)
|
||||
if s.position != 0:
|
||||
if s.position != 0:
|
||||
result.add('%')
|
||||
encodeVInt(s.position, result)
|
||||
if s.offset != - 1:
|
||||
|
|
@ -383,7 +383,7 @@ proc createDb() =
|
|||
fullpath varchar(256) not null,
|
||||
interfHash varchar(256) not null,
|
||||
fullHash varchar(256) not null,
|
||||
|
||||
|
||||
created timestamp not null default (DATETIME('now')),
|
||||
);""")
|
||||
|
||||
|
|
@ -397,7 +397,7 @@ proc createDb() =
|
|||
|
||||
foreign key (module) references module(id)
|
||||
);""")
|
||||
|
||||
|
||||
db.exec(sql"""
|
||||
create table if not exists Type(
|
||||
id integer primary key,
|
||||
|
|
|
|||
|
|
@ -159,6 +159,17 @@ proc genArgNoParam(p: BProc, n: PNode): Rope =
|
|||
initLocExprSingleUse(p, n, a)
|
||||
result = rdLoc(a)
|
||||
|
||||
template genParamLoop(params) {.dirty.} =
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
let paramType = typ.n.sons[i]
|
||||
if not paramType.typ.isCompileTimeOnly:
|
||||
if params != nil: add(params, ~", ")
|
||||
add(params, genArg(p, ri.sons[i], paramType.sym, ri))
|
||||
else:
|
||||
if params != nil: add(params, ~", ")
|
||||
add(params, genArgNoParam(p, ri.sons[i]))
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
var op: TLoc
|
||||
# this is a hotspot in the compiler
|
||||
|
|
@ -170,13 +181,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
var length = sonsLen(ri)
|
||||
for i in countup(1, length - 1):
|
||||
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||
if params != nil: add(params, ~", ")
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
add(params, genArgNoParam(p, ri.sons[i]))
|
||||
genParamLoop(params)
|
||||
fixupCall(p, le, ri, d, op.r, params)
|
||||
|
||||
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
|
|
@ -198,13 +203,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
var length = sonsLen(ri)
|
||||
for i in countup(1, length - 1):
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if ri.sons[i].typ.isCompileTimeOnly: continue
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
add(pl, genArgNoParam(p, ri.sons[i]))
|
||||
if i < length - 1: add(pl, ~", ")
|
||||
genParamLoop(pl)
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
|
||||
|
|
@ -241,13 +240,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
genCallPattern()
|
||||
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
if ri.sons[i].typ.isCompileTimeOnly:
|
||||
result = nil
|
||||
elif i < sonsLen(typ):
|
||||
if i < sonsLen(typ):
|
||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||
# any nkHiddenAddr when it's a 'var T'.
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
|
||||
let paramType = typ.n.sons[i]
|
||||
assert(paramType.kind == nkSym)
|
||||
if paramType.typ.isCompileTimeOnly:
|
||||
result = nil
|
||||
elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
|
||||
result = genArgNoParam(p, ri.sons[i][0])
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
|
|||
|
||||
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
if src.s == OnStatic:
|
||||
flags + {needToCopy}
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - {needToCopy}
|
||||
|
|
@ -238,7 +238,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
|||
t: PNode) =
|
||||
if t == nil: return
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
if src.s == OnStatic:
|
||||
flags + {needToCopy}
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - {needToCopy}
|
||||
|
|
@ -287,13 +287,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
|||
of tyRef:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
of tySequence:
|
||||
if needToCopy notin flags and src.k != locData:
|
||||
if needToCopy notin flags and src.s != OnStatic:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
|
||||
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
|
||||
of tyString:
|
||||
if needToCopy notin flags and src.k != locData:
|
||||
if needToCopy notin flags and src.s != OnStatic:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
else:
|
||||
if dest.s == OnStack or not usesNativeGC():
|
||||
|
|
@ -347,8 +347,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
|||
else:
|
||||
useStringh(p.module)
|
||||
linefmt(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
|
||||
rdLoc(dest), rdLoc(src))
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
rdLoc(dest), rdLoc(src), getTypeDesc(p.module, ty))
|
||||
of tyOpenArray, tyVarargs:
|
||||
# open arrays are always on the stack - really? What if a sequence is
|
||||
# passed to an open array?
|
||||
|
|
@ -413,7 +413,7 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
|
|||
var a: TLoc
|
||||
if d.k != locNone:
|
||||
# need to generate an assignment here
|
||||
initLoc(a, locData, t, OnUnknown)
|
||||
initLoc(a, locData, t, OnStatic)
|
||||
a.r = r
|
||||
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
|
||||
else: genAssignment(p, d, a, {needToCopy})
|
||||
|
|
@ -424,11 +424,11 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
|
|||
d.t = t
|
||||
d.r = r
|
||||
|
||||
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
|
||||
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope; s=OnUnknown) =
|
||||
var a: TLoc
|
||||
if d.k != locNone:
|
||||
# need to generate an assignment here
|
||||
initLoc(a, locExpr, t, OnUnknown)
|
||||
initLoc(a, locExpr, t, s)
|
||||
a.r = r
|
||||
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
|
||||
else: genAssignment(p, d, a, {needToCopy})
|
||||
|
|
@ -503,13 +503,13 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
|||
"$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n",
|
||||
"$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n",
|
||||
"$# = #modInt($#, $#);$n",
|
||||
"$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
|
||||
prc64: array[mAddI..mPred, string] = [
|
||||
"$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n",
|
||||
"$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n",
|
||||
"$# = #modInt64($#, $#);$n",
|
||||
"$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
|
||||
"$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n"]
|
||||
opr: array[mAddI..mPred, string] = [
|
||||
"($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
|
||||
"($#)($# / $#)", "($#)($# % $#)",
|
||||
"($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
|
||||
"($#)($# / $#)", "($#)($# % $#)",
|
||||
"($#)($# + $#)", "($#)($# - $#)"]
|
||||
|
|
@ -525,16 +525,16 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
|||
let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
|
||||
putIntoDest(p, d, e.typ, res)
|
||||
else:
|
||||
let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
|
||||
let res = binaryArithOverflowRaw(p, t, a, b,
|
||||
if t.kind == tyInt64: prc64[m] else: prc[m])
|
||||
putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
|
||||
|
||||
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
const
|
||||
opr: array[mUnaryMinusI..mAbsI64, string] = [
|
||||
opr: array[mUnaryMinusI..mAbsI, string] = [
|
||||
mUnaryMinusI: "((NI$2)-($1))",
|
||||
mUnaryMinusI64: "-($1)",
|
||||
mAbsI: "($1 > 0? ($1) : -($1))",
|
||||
mAbsI64: "($1 > 0? ($1) : -($1))"]
|
||||
mAbsI: "($1 > 0? ($1) : -($1))"]
|
||||
var
|
||||
a: TLoc
|
||||
t: PType
|
||||
|
|
@ -561,11 +561,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
"($4)($1 ^ $2)", # BitxorI
|
||||
"(($1 <= $2) ? $1 : $2)", # MinI
|
||||
"(($1 >= $2) ? $1 : $2)", # MaxI
|
||||
"($4)((NU64)($1) >> (NU64)($2))", # ShrI64
|
||||
"($4)((NU64)($1) << (NU64)($2))", # ShlI64
|
||||
"($4)($1 & $2)", # BitandI64
|
||||
"($4)($1 | $2)", # BitorI64
|
||||
"($4)($1 ^ $2)", # BitxorI64
|
||||
"(($1 <= $2) ? $1 : $2)", # MinF64
|
||||
"(($1 >= $2) ? $1 : $2)", # MaxF64
|
||||
"($4)((NU$3)($1) + (NU$3)($2))", # AddU
|
||||
|
|
@ -576,9 +571,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
"($1 == $2)", # EqI
|
||||
"($1 <= $2)", # LeI
|
||||
"($1 < $2)", # LtI
|
||||
"($1 == $2)", # EqI64
|
||||
"($1 <= $2)", # LeI64
|
||||
"($1 < $2)", # LtI64
|
||||
"($1 == $2)", # EqF64
|
||||
"($1 <= $2)", # LeF64
|
||||
"($1 < $2)", # LtF64
|
||||
|
|
@ -638,7 +630,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
|
||||
"$1", # UnaryPlusI
|
||||
"($3)((NU$2) ~($1))", # BitnotI
|
||||
"($3)((NU$2) ~($1))", # BitnotI64
|
||||
"$1", # UnaryPlusF64
|
||||
"-($1)", # UnaryMinusF64
|
||||
"($1 > 0? ($1) : -($1))", # AbsF64; BUGFIX: fabs() makes problems
|
||||
|
|
@ -694,7 +685,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
|||
d.s = OnUnknown
|
||||
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
|
||||
e.kind == nkHiddenDeref:
|
||||
putIntoDest(p, d, e.typ, rdLoc(a))
|
||||
putIntoDest(p, d, e.typ, rdLoc(a), a.s)
|
||||
return
|
||||
of tyPtr:
|
||||
d.s = OnUnknown # BUGFIX!
|
||||
|
|
@ -703,7 +694,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
|||
let typ = skipTypes(a.t, abstractInst)
|
||||
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
|
||||
e.kind == nkHiddenDeref:
|
||||
putIntoDest(p, d, e.typ, rdLoc(a))
|
||||
putIntoDest(p, d, e.typ, rdLoc(a), a.s)
|
||||
return
|
||||
if enforceDeref and mt == ctPtrToArray:
|
||||
# we lie about the type for better C interop: 'ptr array[3,T]' is
|
||||
|
|
@ -711,23 +702,23 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
|||
# See tmissingderef. So we get rid of the deref instead. The codegen
|
||||
# ends up using 'memcpy' for the array assignment,
|
||||
# so the '&' and '*' cancel out:
|
||||
putIntoDest(p, d, a.t.sons[0], rdLoc(a))
|
||||
putIntoDest(p, d, a.t.sons[0], rdLoc(a), a.s)
|
||||
else:
|
||||
putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)])
|
||||
putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)], a.s)
|
||||
|
||||
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||
# careful 'addr(myptrToArray)' needs to get the ampersand:
|
||||
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
putIntoDest(p, d, e.typ, "&" & a.r)
|
||||
putIntoDest(p, d, e.typ, "&" & a.r, a.s)
|
||||
#Message(e.info, warnUser, "HERE NEW &")
|
||||
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
|
||||
expr(p, e.sons[0], d)
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
putIntoDest(p, d, e.typ, addrLoc(a))
|
||||
putIntoDest(p, d, e.typ, addrLoc(a), a.s)
|
||||
|
||||
template inheritLocation(d: var TLoc, a: TLoc) =
|
||||
if d.k == locNone: d.s = a.s
|
||||
|
|
@ -754,7 +745,18 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
|
||||
else: internalError(e.info, "genTupleElem")
|
||||
addf(r, ".Field$1", [rope(i)])
|
||||
putIntoDest(p, d, ty.sons[i], r)
|
||||
putIntoDest(p, d, ty.sons[i], r, a.s)
|
||||
|
||||
proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope): PSym =
|
||||
var ty = ty
|
||||
assert r != nil
|
||||
while ty != nil:
|
||||
assert(ty.kind in {tyTuple, tyObject})
|
||||
result = lookupInRecord(ty.n, field.name)
|
||||
if result != nil: break
|
||||
if not p.module.compileToCpp: add(r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if result == nil: internalError(field.info, "genCheckedRecordField")
|
||||
|
||||
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
|
|
@ -765,25 +767,18 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
|||
# we found a unique tuple type which lacks field information
|
||||
# so we use Field$i
|
||||
addf(r, ".Field$1", [rope(f.position)])
|
||||
putIntoDest(p, d, f.typ, r)
|
||||
putIntoDest(p, d, f.typ, r, a.s)
|
||||
else:
|
||||
var field: PSym = nil
|
||||
while ty != nil:
|
||||
if ty.kind notin {tyTuple, tyObject}:
|
||||
internalError(e.info, "genRecordField")
|
||||
field = lookupInRecord(ty.n, f.name)
|
||||
if field != nil: break
|
||||
if not p.module.compileToCpp: add(r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil: internalError(e.info, "genRecordField 2 ")
|
||||
let field = lookupFieldAgain(p, ty, f, r)
|
||||
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
|
||||
addf(r, ".$1", [field.loc.r])
|
||||
putIntoDest(p, d, field.typ, r)
|
||||
putIntoDest(p, d, field.typ, r, a.s)
|
||||
#d.s = a.s
|
||||
|
||||
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
|
||||
|
||||
proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||
proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
|
||||
origTy: PType) =
|
||||
var test, u, v: TLoc
|
||||
for i in countup(1, sonsLen(e) - 1):
|
||||
var it = e.sons[i]
|
||||
|
|
@ -795,8 +790,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
|||
assert(disc.kind == nkSym)
|
||||
initLoc(test, locNone, it.typ, OnStack)
|
||||
initLocExpr(p, it.sons[1], u)
|
||||
initLoc(v, locExpr, disc.typ, OnUnknown)
|
||||
v.r = "$1.$2" % [obj, disc.sym.loc.r]
|
||||
var o = obj
|
||||
let d = lookupFieldAgain(p, origTy, disc.sym, o)
|
||||
initLoc(v, locExpr, d.typ, OnUnknown)
|
||||
v.r = o
|
||||
v.r.add(".")
|
||||
v.r.add(d.loc.r)
|
||||
genInExprAux(p, it, u, v, test)
|
||||
let id = nodeTableTestOrSet(p.module.dataCache,
|
||||
newStrNode(nkStrLit, field.name.s), gBackendId)
|
||||
|
|
@ -813,27 +812,16 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
|||
|
||||
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
if optFieldCheck in p.options:
|
||||
var
|
||||
a: TLoc
|
||||
f, field: PSym
|
||||
ty: PType
|
||||
r: Rope
|
||||
ty = genRecordFieldAux(p, e.sons[0], d, a)
|
||||
r = rdLoc(a)
|
||||
f = e.sons[0].sons[1].sym
|
||||
field = nil
|
||||
while ty != nil:
|
||||
assert(ty.kind in {tyTuple, tyObject})
|
||||
field = lookupInRecord(ty.n, f.name)
|
||||
if field != nil: break
|
||||
if not p.module.compileToCpp: add(r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil: internalError(e.info, "genCheckedRecordField")
|
||||
var a: TLoc
|
||||
let ty = genRecordFieldAux(p, e.sons[0], d, a)
|
||||
var r = rdLoc(a)
|
||||
let f = e.sons[0].sons[1].sym
|
||||
let field = lookupFieldAgain(p, ty, f, r)
|
||||
if field.loc.r == nil:
|
||||
internalError(e.info, "genCheckedRecordField") # generate the checks:
|
||||
genFieldCheck(p, e, r, field)
|
||||
genFieldCheck(p, e, r, field, ty)
|
||||
add(r, rfmt(nil, ".$1", field.loc.r))
|
||||
putIntoDest(p, d, field.typ, r)
|
||||
putIntoDest(p, d, field.typ, r, a.s)
|
||||
else:
|
||||
genRecordField(p, e.sons[0], d)
|
||||
|
||||
|
|
@ -860,7 +848,7 @@ proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
|||
localError(x.info, errIndexOutOfBounds)
|
||||
d.inheritLocation(a)
|
||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
|
||||
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.s)
|
||||
|
||||
proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
|
|
@ -869,7 +857,7 @@ proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
|
|||
var ty = skipTypes(a.t, abstractVarRange)
|
||||
if d.k == locNone: d.s = a.s
|
||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s)
|
||||
|
||||
proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
|
|
@ -880,7 +868,7 @@ proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
|||
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
|
||||
if d.k == locNone: d.s = a.s
|
||||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s)
|
||||
|
||||
proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
|
|
@ -903,7 +891,7 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
|||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
a.r = rfmt(nil, "(*$1)", a.r)
|
||||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
|
||||
|
||||
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||
|
|
@ -1061,9 +1049,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
|||
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
||||
# seq->data[seq->len-1] = x;
|
||||
let seqAppendPattern = if not p.module.compileToCpp:
|
||||
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
||||
"$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n"
|
||||
else:
|
||||
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
||||
"$1 = ($2) #incrSeqV2($1, sizeof($3));$n"
|
||||
var a, b, dest: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
|
|
@ -1073,8 +1061,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
|||
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
|
||||
keepAlive(p, a)
|
||||
initLoc(dest, locExpr, b.t, OnHeap)
|
||||
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p))
|
||||
dest.r = rfmt(nil, "$1->data[$1->$2]", rdLoc(a), lenField(p))
|
||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||
lineCg(p, cpsStmts, "++$1->$2;$n", rdLoc(a), lenField(p))
|
||||
gcUsage(e)
|
||||
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
|
|
@ -1158,20 +1147,15 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
|||
else:
|
||||
constructLoc(p, tmp)
|
||||
discard getTypeDesc(p.module, t)
|
||||
let ty = getUniqueType(t)
|
||||
for i in 1 .. <e.len:
|
||||
let it = e.sons[i]
|
||||
var tmp2: TLoc
|
||||
tmp2.r = r
|
||||
var field: PSym = nil
|
||||
var ty = getUniqueType(t)
|
||||
while ty != nil:
|
||||
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
||||
if field != nil: break
|
||||
if not p.module.compileToCpp: add(tmp2.r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
|
||||
let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r)
|
||||
if field.loc.r == nil: internalError(e.info, "genObjConstr")
|
||||
if it.len == 3 and optFieldCheck in p.options:
|
||||
genFieldCheck(p, it.sons[2], tmp2.r, field)
|
||||
genFieldCheck(p, it.sons[2], r, field, ty)
|
||||
add(tmp2.r, ".")
|
||||
add(tmp2.r, field.loc.r)
|
||||
tmp2.k = locTemp
|
||||
|
|
@ -1280,7 +1264,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
|||
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
|
||||
else:
|
||||
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
|
||||
putIntoDest(p, d, getSysType(tyBool), r)
|
||||
putIntoDest(p, d, getSysType(tyBool), r, a.s)
|
||||
|
||||
proc genOf(p: BProc, n: PNode, d: var TLoc) =
|
||||
genOf(p, n.sons[1], n.sons[2].typ, d)
|
||||
|
|
@ -1292,45 +1276,47 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
|||
case t.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]), a.s)
|
||||
of tyFloat..tyFloat128:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]), a.s)
|
||||
of tyBool:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]))
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]), a.s)
|
||||
of tyChar:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]))
|
||||
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)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t)]))
|
||||
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyString:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]))
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s)
|
||||
of tySet:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [
|
||||
addrLoc(a), genTypeInfo(p.module, t)]))
|
||||
addrLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyOpenArray, tyVarargs:
|
||||
var b: TLoc
|
||||
case a.t.kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)])
|
||||
putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)], a.s)
|
||||
of tyString, tySequence:
|
||||
putIntoDest(p, b, e.typ,
|
||||
"$1->data, $1->$2" % [rdLoc(a), lenField(p)])
|
||||
"$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.s)
|
||||
of tyArray, tyArrayConstr:
|
||||
putIntoDest(p, b, e.typ,
|
||||
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))])
|
||||
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.s)
|
||||
else: internalError(e.sons[0].info, "genRepr()")
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
|
||||
genTypeInfo(p.module, elemType(t))]))
|
||||
genTypeInfo(p.module, elemType(t))]), a.s)
|
||||
of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
|
||||
tySequence:
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprAny($1, $2)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t)]))
|
||||
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
of tyEmpty:
|
||||
localError(e.info, "'repr' doesn't support 'void' type")
|
||||
else:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
|
||||
[addrLoc(a), genTypeInfo(p.module, t)]))
|
||||
[addrLoc(a), genTypeInfo(p.module, t)]), a.s)
|
||||
gcUsage(e)
|
||||
|
||||
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
|
@ -1492,11 +1478,11 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
of 1, 2, 4, 8:
|
||||
case op
|
||||
of mIncl:
|
||||
var ts = "NI" & $(size * 8)
|
||||
var ts = "NU" & $(size * 8)
|
||||
binaryStmtInExcl(p, e, d,
|
||||
"$1 |= ((" & ts & ")1)<<(($2)%(sizeof(" & ts & ")*8));$n")
|
||||
of mExcl:
|
||||
var ts = "NI" & $(size * 8)
|
||||
var ts = "NU" & $(size * 8)
|
||||
binaryStmtInExcl(p, e, d, "$1 &= ~(((" & ts & ")1) << (($2) % (sizeof(" &
|
||||
ts & ")*8)));$n")
|
||||
of mCard:
|
||||
|
|
@ -1555,13 +1541,13 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
|||
let etyp = skipTypes(e.typ, abstractRange)
|
||||
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
|
||||
putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
|
||||
[getTypeDesc(p.module, e.typ), addrLoc(a)])
|
||||
[getTypeDesc(p.module, e.typ), addrLoc(a)], a.s)
|
||||
elif etyp.kind == tyProc and etyp.callConv == ccClosure:
|
||||
putIntoDest(p, d, e.typ, "(($1) ($2))" %
|
||||
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])
|
||||
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.s)
|
||||
else:
|
||||
putIntoDest(p, d, e.typ, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)])
|
||||
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
|
||||
|
||||
proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
const floatTypes = {tyFloat..tyFloat128}
|
||||
|
|
@ -1581,7 +1567,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
|||
tmp.s = OnStack
|
||||
tmp.flags = {}
|
||||
expr(p, e.sons[1], tmp)
|
||||
putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl])
|
||||
putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl], tmp.s)
|
||||
else:
|
||||
# I prefer the shorter cast version for pointer types -> generate less
|
||||
# C code; plus it's the right thing to do for closures:
|
||||
|
|
@ -1591,16 +1577,17 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
|
|||
var a: TLoc
|
||||
var dest = skipTypes(n.typ, abstractVar)
|
||||
# range checks for unsigned turned out to be buggy and annoying:
|
||||
if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
|
||||
if optRangeCheck notin p.options or dest.skipTypes({tyRange}).kind in
|
||||
{tyUInt..tyUInt64}:
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
putIntoDest(p, d, n.typ, "(($1) ($2))" %
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)])
|
||||
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.s)
|
||||
else:
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
|
||||
getTypeDesc(p.module, dest), rdCharLoc(a),
|
||||
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
|
||||
rope(magic)]))
|
||||
rope(magic)]), a.s)
|
||||
|
||||
proc genConv(p: BProc, e: PNode, d: var TLoc) =
|
||||
let destType = e.typ.skipTypes({tyVar, tyGenericInst})
|
||||
|
|
@ -1612,13 +1599,13 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
|
|||
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)])
|
||||
putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)], a.s)
|
||||
|
||||
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
putIntoDest(p, d, skipTypes(n.typ, abstractVar),
|
||||
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]))
|
||||
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.s)
|
||||
gcUsage(n)
|
||||
|
||||
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
|
@ -1661,7 +1648,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
case op
|
||||
of mOr, mAnd: genAndOr(p, e, d, op)
|
||||
of mNot..mToBiggestInt: unaryArith(p, e, d, op)
|
||||
of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op)
|
||||
of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op)
|
||||
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
|
||||
of mShrI..mXor: binaryArith(p, e, d, op)
|
||||
of mEqProc: genEqProc(p, e, d)
|
||||
|
|
@ -1746,6 +1733,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
of mEcho: genEcho(p, e[1].skipConv)
|
||||
of mArrToSeq: genArrToSeq(p, e, d)
|
||||
of mNLen..mNError, mSlurp..mQuoteAst:
|
||||
echo "from here ", p.prc.name.s, " ", p.prc.info
|
||||
writestacktrace()
|
||||
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
|
||||
of mSpawn:
|
||||
let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
|
||||
|
|
@ -1768,7 +1757,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
|||
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), OnHeap)
|
||||
fillLoc(d, locData, t, "TMP" & rope(id), OnStatic)
|
||||
if id == gBackendId:
|
||||
# expression not found in the cache:
|
||||
inc(gBackendId)
|
||||
|
|
@ -1807,7 +1796,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
|||
[rdLoc(d), rdSetElemLoc(a, e.typ)])
|
||||
else:
|
||||
# small set
|
||||
var ts = "NI" & $(getSize(e.typ) * 8)
|
||||
var ts = "NU" & $(getSize(e.typ) * 8)
|
||||
lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
|
||||
for i in countup(0, sonsLen(e) - 1):
|
||||
if e.sons[i].kind == nkRange:
|
||||
|
|
@ -1815,13 +1804,13 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
|||
initLocExpr(p, e.sons[i].sons[0], a)
|
||||
initLocExpr(p, e.sons[i].sons[1], b)
|
||||
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
|
||||
"$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [
|
||||
"$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [
|
||||
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
|
||||
rdSetElemLoc(b, e.typ)])
|
||||
else:
|
||||
initLocExpr(p, e.sons[i], a)
|
||||
lineF(p, cpsStmts,
|
||||
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
|
||||
"$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n",
|
||||
[rdLoc(d), rdSetElemLoc(a, e.typ)])
|
||||
|
||||
proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
|
|
@ -1854,7 +1843,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
|||
var tmp = "LOC" & rope(p.labels)
|
||||
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
|
||||
putIntoDest(p, d, n.typ, tmp)
|
||||
putIntoDest(p, d, n.typ, tmp, OnStatic)
|
||||
else:
|
||||
var tmp, a, b: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
|
|
@ -1908,10 +1897,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
r, genTypeInfo(p.module, dest))
|
||||
if n.sons[0].typ.kind != tyObject:
|
||||
putIntoDest(p, d, n.typ,
|
||||
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)])
|
||||
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.s)
|
||||
else:
|
||||
putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
|
||||
[getTypeDesc(p.module, dest), addrLoc(a)])
|
||||
[getTypeDesc(p.module, dest), addrLoc(a)], a.s)
|
||||
|
||||
proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
if p.module.compileToCpp:
|
||||
|
|
@ -1943,9 +1932,9 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
|
||||
else:
|
||||
r = "&" & r
|
||||
putIntoDest(p, d, n.typ, r)
|
||||
putIntoDest(p, d, n.typ, r, a.s)
|
||||
else:
|
||||
putIntoDest(p, d, n.typ, r)
|
||||
putIntoDest(p, d, n.typ, r, a.s)
|
||||
|
||||
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
var t = getUniqueType(n.typ)
|
||||
|
|
@ -1960,7 +1949,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
|||
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
||||
|
||||
if d.k == locNone:
|
||||
fillLoc(d, locData, t, tmp, OnHeap)
|
||||
fillLoc(d, locData, t, tmp, OnStatic)
|
||||
else:
|
||||
putDataIntoDest(p, d, t, tmp)
|
||||
|
||||
|
|
@ -1978,6 +1967,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
genProc(p.module, sym)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skProc, skConverter, skIterators:
|
||||
if sfCompileTime in sym.flags:
|
||||
localError(n.info, "request to generate code for .compileTime proc: " &
|
||||
sym.name.s)
|
||||
genProc(p.module, sym)
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
internalError(n.info, "expr: proc not init " & sym.name.s)
|
||||
|
|
@ -1987,7 +1979,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
elif isSimpleConst(sym.typ):
|
||||
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ))
|
||||
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic)
|
||||
else:
|
||||
genComplexConst(p, sym, d)
|
||||
of skEnumField:
|
||||
|
|
@ -2074,6 +2066,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i])
|
||||
of nkIfExpr, nkIfStmt: genIf(p, n, d)
|
||||
of nkWhen:
|
||||
# This should be a "when nimvm" node.
|
||||
expr(p, n.sons[1].sons[0], d)
|
||||
of nkObjDownConv: downConv(p, n, d)
|
||||
of nkObjUpConv: upConv(p, n, d)
|
||||
of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF")
|
||||
|
|
@ -2128,7 +2123,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||
# are not transformed correctly. We work around this issue (#411) here
|
||||
# by ensuring it's no inner proc (owner is a module):
|
||||
if prc.skipGenericOwner.kind == skModule:
|
||||
if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
||||
if (optDeadCodeElim notin gGlobalOptions and
|
||||
sfDeadCodeElim notin getModule(prc).flags) or
|
||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||
|
|
@ -2150,7 +2145,7 @@ proc genNamedConstExpr(p: BProc, n: PNode): Rope =
|
|||
proc genConstSimpleList(p: BProc, n: PNode): Rope =
|
||||
var length = sonsLen(n)
|
||||
result = rope("{")
|
||||
for i in countup(0, length - 2):
|
||||
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]))
|
||||
addf(result, "}$n", [])
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ proc assignLabel(b: var TBlock): Rope {.inline.} =
|
|||
proc blockBody(b: var TBlock): Rope =
|
||||
result = b.sections[cpsLocals]
|
||||
if b.frameLen > 0:
|
||||
result.addf("F.len+=$1;$n", [b.frameLen.rope])
|
||||
result.addf("FR.len+=$1;$n", [b.frameLen.rope])
|
||||
result.add(b.sections[cpsInit])
|
||||
result.add(b.sections[cpsStmts])
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ proc endBlock(p: BProc) =
|
|||
~"}$n"
|
||||
let frameLen = p.blocks[topBlock].frameLen
|
||||
if frameLen > 0:
|
||||
blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
|
||||
blockEnd.addf("FR.len-=$1;$n", [frameLen.rope])
|
||||
endBlock(p, blockEnd)
|
||||
|
||||
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||
|
|
@ -1002,8 +1002,10 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
|||
proc determineSection(n: PNode): TCFileSection =
|
||||
result = cfsProcHeaders
|
||||
if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
|
||||
if n.sons[0].strVal.startsWith("/*TYPESECTION*/"): result = cfsTypes
|
||||
elif n.sons[0].strVal.startsWith("/*VARSECTION*/"): result = cfsVars
|
||||
let sec = n.sons[0].strVal
|
||||
if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes
|
||||
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
|
||||
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
|
||||
|
||||
proc genEmit(p: BProc, t: PNode) =
|
||||
var s = genAsmOrEmitStmt(p, t.sons[1])
|
||||
|
|
@ -1099,7 +1101,10 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
|||
genGotoVar(p, e.sons[1])
|
||||
elif not fieldDiscriminantCheckNeeded(p, e):
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if e[0].kind in {nkDerefExpr, nkHiddenDeref}:
|
||||
genDeref(p, e[0], a, enforceDeref=true)
|
||||
else:
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if fastAsgn: incl(a.flags, lfNoDeepCopy)
|
||||
assert(a.t != nil)
|
||||
loadInto(p, e.sons[0], e.sons[1], a)
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
|
|||
result = OnUnknown
|
||||
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||
check: var IntSet, declareEnvironment=true) =
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
rettype = ~"void"
|
||||
|
|
@ -341,6 +342,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
|||
add(params, ~"*")
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
elif weakDep:
|
||||
add(params, getTypeDescWeak(m, param.typ, check))
|
||||
else:
|
||||
add(params, getTypeDescAux(m, param.typ, check))
|
||||
add(params, ~" ")
|
||||
|
|
@ -438,6 +441,8 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
|||
elif fieldType.kind == tySequence:
|
||||
# we need to use a weak dependency here for trecursive_table.
|
||||
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||
elif field.bitsize != 0:
|
||||
addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
|
|
@ -577,7 +582,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
|||
result = getTypeName(t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
var rettype, desc: Rope
|
||||
genProcParams(m, t, rettype, desc, check)
|
||||
genProcParams(m, t, rettype, desc, check, true, true)
|
||||
if not isImportedType(t):
|
||||
if t.callConv != ccClosure: # procedure vars may need a closure!
|
||||
addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,10 @@ proc getUniqueType*(key: PType): PType =
|
|||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||
internalError("getUniqueType")
|
||||
if key.sym != nil:
|
||||
internalError(key.sym.info, "metatype not eliminated")
|
||||
else:
|
||||
internalError("metatype not eliminated")
|
||||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@
|
|||
## This module implements the C code generator.
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp,
|
||||
options, intsets,
|
||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||
ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
|
||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
||||
semparallel
|
||||
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
|
||||
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
|
||||
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||
lowerings, semparallel
|
||||
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
|
|
@ -376,7 +375,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
|||
var a = "&" & s.loc.r
|
||||
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
|
||||
lineF(p, cpsInit,
|
||||
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
|
||||
"FR.s[$1].address = (void*)$3; FR.s[$1].typ = $4; FR.s[$1].name = $2;$n",
|
||||
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
|
||||
genTypeInfo(p.module, s.loc.t)])
|
||||
inc(p.maxFrameLen)
|
||||
|
|
@ -506,8 +505,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
|||
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
|
||||
var s: TStringSeq = @[]
|
||||
libCandidates(lib.path.strVal, s)
|
||||
if gVerbosity >= 2:
|
||||
msgWriteln("Dependency: " & lib.path.strVal)
|
||||
rawMessage(hintDependency, lib.path.strVal)
|
||||
var loadlib: Rope = nil
|
||||
for i in countup(0, high(s)):
|
||||
inc(m.labels)
|
||||
|
|
@ -599,7 +597,7 @@ proc cgsym(m: BModule, name: string): Rope =
|
|||
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
|
||||
of skVar, skResult, skLet: genVarPrototype(m, sym)
|
||||
of skType: discard getTypeDesc(m, sym.typ)
|
||||
else: internalError("cgsym: " & name)
|
||||
else: internalError("cgsym: " & name & ": " & $sym.kind)
|
||||
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
|
||||
|
|
@ -611,10 +609,12 @@ proc generateHeaders(m: BModule) =
|
|||
add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
|
||||
var it = PStrEntry(m.headerFiles.head)
|
||||
while it != nil:
|
||||
if it.data[0] notin {'\"', '<'}:
|
||||
addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
|
||||
if it.data[0] == '#':
|
||||
add(m.s[cfsHeaders], rope(it.data.replace('`', '"') & tnl))
|
||||
elif it.data[0] notin {'\"', '<'}:
|
||||
addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it.data)])
|
||||
else:
|
||||
addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
|
||||
addf(m.s[cfsHeaders], "#include $1$N", [rope(it.data)])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc retIsNotVoid(s: PSym): bool =
|
||||
|
|
@ -623,7 +623,7 @@ proc retIsNotVoid(s: PSym): bool =
|
|||
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
if p.maxFrameLen > 0:
|
||||
discard cgsym(p.module, "TVarSlot")
|
||||
discard cgsym(p.module, "VarSlot")
|
||||
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
|
||||
procname, filename, p.maxFrameLen.rope,
|
||||
p.blocks[0].frameLen.rope)
|
||||
|
|
@ -676,8 +676,11 @@ proc genProcAux(m: BModule, prc: PSym) =
|
|||
closureSetup(p, prc)
|
||||
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: Rope
|
||||
if sfNoReturn in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
|
||||
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
|
||||
|
|
@ -718,10 +721,14 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
|||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
|
||||
header = "extern \"C\" " & header
|
||||
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
||||
if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
|
||||
header.add(" __attribute__((naked))")
|
||||
if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
|
||||
header.add(" __attribute__((noreturn))")
|
||||
add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
|
|
@ -753,7 +760,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
|||
var m = p.module
|
||||
useHeader(m, sym)
|
||||
if sym.loc.k == locNone:
|
||||
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
|
||||
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnStatic)
|
||||
if lfNoDecl in sym.loc.flags: return
|
||||
# declare implementation:
|
||||
var q = findPendingModule(m, sym)
|
||||
|
|
@ -808,7 +815,7 @@ proc genVarPrototype(m: BModule, sym: PSym) =
|
|||
genVarPrototypeAux(m, sym)
|
||||
|
||||
proc addIntTypes(result: var Rope) {.inline.} =
|
||||
addf(result, "#define NIM_INTBITS $1", [
|
||||
addf(result, "#define NIM_INTBITS $1" & tnl, [
|
||||
platform.CPU[targetCPU].intSize.rope])
|
||||
|
||||
proc getCopyright(cfile: string): Rope =
|
||||
|
|
@ -846,14 +853,14 @@ proc genMainProc(m: BModule) =
|
|||
# functions, which might otherwise merge their stack frames.
|
||||
PreMainBody =
|
||||
"void PreMainInner() {$N" &
|
||||
"\tsystemInit();$N" &
|
||||
"\tsystemInit000();$N" &
|
||||
"$1" &
|
||||
"$2" &
|
||||
"$3" &
|
||||
"}$N$N" &
|
||||
"void PreMain() {$N" &
|
||||
"\tvoid (*volatile inner)();$N" &
|
||||
"\tsystemDatInit();$N" &
|
||||
"\tsystemDatInit000();$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$4$5" &
|
||||
"\t(*inner)();$N" &
|
||||
|
|
@ -943,7 +950,7 @@ proc genMainProc(m: BModule) =
|
|||
gBreakpoints.add(m.genFilenames)
|
||||
|
||||
let initStackBottomCall =
|
||||
if platform.targetOS == osStandalone: "".rope
|
||||
if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
|
|
@ -967,8 +974,8 @@ proc getSomeInitName(m: PSym, suffix: string): Rope =
|
|||
result.add m.name.s
|
||||
result.add suffix
|
||||
|
||||
proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init")
|
||||
proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit")
|
||||
proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init000")
|
||||
proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit000")
|
||||
|
||||
proc registerModuleToMain(m: PSym) =
|
||||
var
|
||||
|
|
@ -1010,7 +1017,7 @@ proc genInitCode(m: BModule) =
|
|||
var procname = makeCString(m.module.name.s)
|
||||
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
else:
|
||||
add(prc, ~"\tTFrame F; F.len = 0;$N")
|
||||
add(prc, ~"\tTFrame F; FR.len = 0;$N")
|
||||
|
||||
add(prc, genSectionStart(cpsInit))
|
||||
add(prc, m.preInitProc.s(cpsInit))
|
||||
|
|
@ -1103,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
|||
|
||||
proc nullify[T](arr: var T) =
|
||||
for i in low(arr)..high(arr):
|
||||
arr[i] = nil
|
||||
arr[i] = Rope(nil)
|
||||
|
||||
proc resetModule*(m: BModule) =
|
||||
# between two compilations in CAAS mode, we can throw
|
||||
|
|
@ -1322,4 +1329,3 @@ proc cgenWriteModules* =
|
|||
if generatedHeader != nil: writeHeader(generatedHeader)
|
||||
|
||||
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,33 +9,33 @@
|
|||
|
||||
## This module implements code generation for multi methods.
|
||||
|
||||
import
|
||||
import
|
||||
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
|
||||
sempass2, strutils
|
||||
|
||||
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
var dest = skipTypes(d, abstractPtrs)
|
||||
var source = skipTypes(n.typ, abstractPtrs)
|
||||
if (source.kind == tyObject) and (dest.kind == tyObject):
|
||||
if (source.kind == tyObject) and (dest.kind == tyObject):
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff == high(int): internalError(n.info, "cgmeth.genConv")
|
||||
if diff < 0:
|
||||
if diff < 0:
|
||||
result = newNodeIT(nkObjUpConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
|
||||
elif diff > 0:
|
||||
elif diff > 0:
|
||||
result = newNodeIT(nkObjDownConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if not downcast:
|
||||
if not downcast:
|
||||
internalError(n.info, "cgmeth.genConv: no downcast allowed")
|
||||
else:
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc methodCall*(n: PNode): PNode =
|
||||
|
||||
proc methodCall*(n: PNode): PNode =
|
||||
result = n
|
||||
# replace ordinary method by dispatcher method:
|
||||
# replace ordinary method by dispatcher method:
|
||||
var disp = lastSon(result.sons[0].sym.ast).sym
|
||||
assert sfDispatcher in disp.flags
|
||||
result.sons[0].sym = disp
|
||||
|
|
@ -47,30 +47,35 @@ proc methodCall*(n: PNode): PNode =
|
|||
var
|
||||
gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[]
|
||||
|
||||
proc sameMethodBucket(a, b: PSym): bool =
|
||||
result = false
|
||||
if a.name.id != b.name.id: return
|
||||
if sonsLen(a.typ) != sonsLen(b.typ):
|
||||
type
|
||||
MethodResult = enum No, Invalid, Yes
|
||||
|
||||
proc sameMethodBucket(a, b: PSym): MethodResult =
|
||||
if a.name.id != b.name.id: return
|
||||
if sonsLen(a.typ) != sonsLen(b.typ):
|
||||
return # check for return type:
|
||||
if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): return
|
||||
for i in countup(1, sonsLen(a.typ) - 1):
|
||||
if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): return
|
||||
for i in countup(1, sonsLen(a.typ) - 1):
|
||||
var aa = a.typ.sons[i]
|
||||
var bb = b.typ.sons[i]
|
||||
while true:
|
||||
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) or
|
||||
(aa.kind == tyObject) and (bb.kind == tyObject) and
|
||||
(inheritanceDiff(bb, aa) < 0):
|
||||
discard
|
||||
else:
|
||||
break
|
||||
if sameType(aa, bb):
|
||||
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
|
||||
elif diff != high(int):
|
||||
result = Invalid
|
||||
else:
|
||||
return
|
||||
result = true
|
||||
return No
|
||||
|
||||
proc attachDispatcher(s: PSym, dispatcher: PNode) =
|
||||
var L = s.ast.len-1
|
||||
|
|
@ -133,18 +138,31 @@ proc fixupDispatcher(meth, disp: PSym) =
|
|||
|
||||
proc methodDef*(s: PSym, fromCache: bool) =
|
||||
var L = len(gMethods)
|
||||
var witness: PSym
|
||||
for i in countup(0, L - 1):
|
||||
var disp = gMethods[i].dispatcher
|
||||
if sameMethodBucket(disp, s):
|
||||
case sameMethodBucket(disp, s)
|
||||
of Yes:
|
||||
add(gMethods[i].methods, s)
|
||||
attachDispatcher(s, lastSon(disp.ast))
|
||||
fixupDispatcher(s, disp)
|
||||
when useEffectSystem: checkMethodEffects(disp, s)
|
||||
return
|
||||
if sfBase in s.flags and gMethods[i].methods[0] != s:
|
||||
# already exists due to forwarding definition?
|
||||
localError(s.info, "method is not a base")
|
||||
return
|
||||
of No: discard
|
||||
of Invalid:
|
||||
if witness.isNil: witness = gMethods[i].methods[0]
|
||||
# create a new dispatcher:
|
||||
add(gMethods, (methods: @[s], dispatcher: createDispatcher(s)))
|
||||
if fromCache:
|
||||
internalError(s.info, "no method dispatcher found")
|
||||
if witness != nil:
|
||||
localError(s.info, "invalid declaration order; cannot attach '" & s.name.s &
|
||||
"' to method defined here: " & $witness.info)
|
||||
elif sfBase notin s.flags:
|
||||
message(s.info, warnUseBase)
|
||||
|
||||
proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
|
|
@ -154,35 +172,35 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
|
|||
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
|
||||
if not sameType(t2, t):
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if contains(relevantCols, col):
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if contains(relevantCols, col):
|
||||
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)):
|
||||
return d
|
||||
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||
# we use shellsort here; fast and simple
|
||||
var n = len(a)
|
||||
var h = 1
|
||||
while true:
|
||||
while true:
|
||||
h = 3 * h + 1
|
||||
if h > n: break
|
||||
while true:
|
||||
if h > n: break
|
||||
while true:
|
||||
h = h div 3
|
||||
for i in countup(h, n - 1):
|
||||
for i in countup(h, n - 1):
|
||||
var v = a[i]
|
||||
var j = i
|
||||
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
|
||||
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
|
||||
a[j] = a[j - h]
|
||||
j = j - h
|
||||
if j < h: break
|
||||
if j < h: break
|
||||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
var base = lastSon(methods[0].ast).sym
|
||||
result = base
|
||||
|
|
@ -199,7 +217,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
|||
addSon(isn, newSymNode(iss))
|
||||
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
|
||||
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
|
||||
if cond != nil:
|
||||
if cond != nil:
|
||||
var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
addSon(a, newSymNode(ands))
|
||||
addSon(a, cond)
|
||||
|
|
@ -209,12 +227,12 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
|||
cond = isn
|
||||
var call = newNodeI(nkCall, base.info)
|
||||
addSon(call, newSymNode(curr))
|
||||
for col in countup(1, paramLen - 1):
|
||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||
for col in countup(1, paramLen - 1):
|
||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||
curr.typ.sons[col], false))
|
||||
var ret: PNode
|
||||
if base.typ.sons[0] != nil:
|
||||
var a = newNodeI(nkAsgn, base.info)
|
||||
var a = newNodeI(nkFastAsgn, base.info)
|
||||
addSon(a, newSymNode(base.ast.sons[resultPos].sym))
|
||||
addSon(a, call)
|
||||
ret = newNodeI(nkReturnStmt, base.info)
|
||||
|
|
@ -230,13 +248,12 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
|||
disp = ret
|
||||
result.ast.sons[bodyPos] = disp
|
||||
|
||||
proc generateMethodDispatchers*(): PNode =
|
||||
proc generateMethodDispatchers*(): PNode =
|
||||
result = newNode(nkStmtList)
|
||||
for bucket in countup(0, len(gMethods) - 1):
|
||||
for bucket in countup(0, len(gMethods) - 1):
|
||||
var relevantCols = initIntSet()
|
||||
for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1):
|
||||
for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1):
|
||||
if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col)
|
||||
sortBucket(gMethods[bucket].methods, relevantCols)
|
||||
addSon(result,
|
||||
newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols)))
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@ template bootSwitch(name, expr, userString: expr): expr =
|
|||
const name = if expr: " " & userString else: ""
|
||||
|
||||
bootSwitch(usedRelease, defined(release), "-d:release")
|
||||
bootSwitch(usedGnuReadline, defined(useGnuReadline), "-d:useGnuReadline")
|
||||
bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
|
||||
bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
|
||||
bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
|
||||
bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
|
||||
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
|
||||
bootSwitch(usedGoGC, defined(gogc), "--gc:go")
|
||||
bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
|
||||
import
|
||||
|
|
@ -64,14 +65,15 @@ proc getCommandLineDesc(): string =
|
|||
|
||||
proc helpOnError(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
msgWriteln(getCommandLineDesc())
|
||||
msgWriteln(getCommandLineDesc(), {msgStdout})
|
||||
msgQuit(0)
|
||||
|
||||
proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||
if pass == passCmd1:
|
||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||
platform.OS[platform.hostOS].name,
|
||||
CPU[platform.hostCPU].name]) & AdvancedUsage)
|
||||
CPU[platform.hostCPU].name]) & AdvancedUsage,
|
||||
{msgStdout})
|
||||
msgQuit(0)
|
||||
|
||||
proc writeVersionInfo(pass: TCmdLinePass) =
|
||||
|
|
@ -86,7 +88,7 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
|||
|
||||
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
||||
usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC)
|
||||
usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC)
|
||||
msgQuit(0)
|
||||
|
||||
var
|
||||
|
|
@ -94,7 +96,7 @@ var
|
|||
|
||||
proc writeCommandLineUsage() =
|
||||
if not helpWritten:
|
||||
msgWriteln(getCommandLineDesc())
|
||||
msgWriteln(getCommandLineDesc(), {msgStdout})
|
||||
helpWritten = true
|
||||
|
||||
proc addPrefix(switch: string): string =
|
||||
|
|
@ -127,6 +129,18 @@ proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
|
|||
of wOff: gOptions = gOptions - op
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo): bool =
|
||||
result = false
|
||||
case whichKeyword(arg)
|
||||
of wOn: gOptions = gOptions + op
|
||||
of wOff: gOptions = gOptions - op
|
||||
else:
|
||||
if arg == "list":
|
||||
result = true
|
||||
else:
|
||||
localError(info, errOnOffOrListExpectedButXFound, arg)
|
||||
|
||||
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
case whichKeyword(arg)
|
||||
|
|
@ -140,6 +154,10 @@ proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||
|
||||
var
|
||||
enableNotes: TNoteKinds
|
||||
disableNotes: TNoteKinds
|
||||
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo; orig: string) =
|
||||
var id = "" # arg = "X]:on|off"
|
||||
|
|
@ -161,8 +179,12 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
|||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||
else: localError(info, "unknown warning: " & id)
|
||||
case whichKeyword(substr(arg, i))
|
||||
of wOn: incl(gNotes, n)
|
||||
of wOff: excl(gNotes, n)
|
||||
of wOn:
|
||||
incl(gNotes, n)
|
||||
incl(enableNotes, n)
|
||||
of wOff:
|
||||
excl(gNotes, n)
|
||||
incl(disableNotes, n)
|
||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processCompile(filename: string) =
|
||||
|
|
@ -181,6 +203,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
|||
of "v2": result = gSelectedGC == gcV2
|
||||
of "markandsweep": result = gSelectedGC == gcMarkAndSweep
|
||||
of "generational": result = gSelectedGC == gcGenerational
|
||||
of "go": result = gSelectedGC == gcGo
|
||||
of "none": result = gSelectedGC == gcNone
|
||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "opt":
|
||||
|
|
@ -229,7 +252,8 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
|||
of "experimental": result = gExperimentalMode
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc processPath(path: string, notRelativeToProj = false): string =
|
||||
proc processPath(path: string, notRelativeToProj = false,
|
||||
cfginfo = unknownLineInfo()): string =
|
||||
let p = if notRelativeToProj or os.isAbsolute(path) or
|
||||
'$' in path or path[0] == '.':
|
||||
path
|
||||
|
|
@ -239,6 +263,7 @@ proc processPath(path: string, notRelativeToProj = false): string =
|
|||
"nim", getPrefixDir(),
|
||||
"lib", libpath,
|
||||
"home", removeTrailingDirSep(os.getHomeDir()),
|
||||
"config", cfginfo.toFullPath().splitFile().dir,
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
|
||||
|
|
@ -281,7 +306,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
case switch.normalize
|
||||
of "path", "p":
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg), info)
|
||||
addPath(processPath(arg, cfginfo=info), info)
|
||||
of "nimblepath", "babelpath":
|
||||
# keep the old name for compat
|
||||
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
||||
|
|
@ -363,14 +388,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "generational":
|
||||
gSelectedGC = gcGenerational
|
||||
defineSymbol("gcgenerational")
|
||||
of "go":
|
||||
gSelectedGC = gcGo
|
||||
defineSymbol("gogc")
|
||||
of "none":
|
||||
gSelectedGC = gcNone
|
||||
defineSymbol("nogc")
|
||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
|
||||
of "warnings", "w":
|
||||
if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings()
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
|
||||
of "hint": processSpecificNote(arg, wHint, pass, info, switch)
|
||||
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
|
||||
of "hints":
|
||||
if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
|
||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
|
||||
|
|
@ -405,6 +435,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
||||
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
||||
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of "reportconceptfailures":
|
||||
processOnOffSwitchG({optReportConceptFailures}, arg, pass, info)
|
||||
of "threads":
|
||||
processOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
#if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
|
||||
|
|
@ -501,6 +533,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "verbosity":
|
||||
expectArg(switch, arg, pass, info)
|
||||
gVerbosity = parseInt(arg)
|
||||
gNotes = NotesVerbosity[gVerbosity]
|
||||
incl(gNotes, enableNotes)
|
||||
excl(gNotes, disableNotes)
|
||||
of "parallelbuild":
|
||||
expectArg(switch, arg, pass, info)
|
||||
gNumberOfProcessors = parseInt(arg)
|
||||
|
|
@ -530,6 +565,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "genscript":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optGenScript)
|
||||
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
|
||||
of "lib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
libpath = processPath(arg, notRelativeToProj=true)
|
||||
|
|
@ -579,6 +615,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "experimental":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
gExperimentalMode = true
|
||||
of "assembler":
|
||||
cAssembler = nameToCC(arg)
|
||||
if cAssembler notin cValidAssemblers:
|
||||
localError(info, errGenerated, "'$1' is not a valid assembler." % [arg])
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
|
@ -608,11 +648,18 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
|
|||
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
argsCount: var int): bool =
|
||||
if argsCount == 0:
|
||||
options.command = p.key
|
||||
# nim filename.nims is the same as "nim e filename.nims":
|
||||
if p.key.endswith(".nims"):
|
||||
options.command = "e"
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
arguments = cmdLineRest(p)
|
||||
result = true
|
||||
elif pass != passCmd2:
|
||||
options.command = p.key
|
||||
else:
|
||||
if pass == passCmd1: options.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
# support UNIX style filenames anywhere for portable build scripts:
|
||||
# support UNIX style filenames everywhere for portable build scripts:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
arguments = cmdLineRest(p)
|
||||
result = true
|
||||
|
|
|
|||
|
|
@ -88,3 +88,8 @@ proc initDefines*() =
|
|||
defineSymbol("nimalias")
|
||||
defineSymbol("nimlocks")
|
||||
defineSymbol("nimnode")
|
||||
defineSymbol("nimnomagic64")
|
||||
defineSymbol("nimvarargstyped")
|
||||
defineSymbol("nimtypedescfixed")
|
||||
defineSymbol("nimKnowsNimvm")
|
||||
defineSymbol("nimArrIdx")
|
||||
|
|
|
|||
147
compiler/crc.nim
147
compiler/crc.nim
|
|
@ -1,147 +0,0 @@
|
|||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
strutils
|
||||
|
||||
type
|
||||
TCrc32* = int32
|
||||
|
||||
const
|
||||
InitCrc32* = TCrc32(- 1)
|
||||
InitAdler32* = int32(1)
|
||||
|
||||
proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
|
||||
proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
|
||||
proc crcFromBuf*(buf: pointer, length: int): TCrc32
|
||||
proc strCrc32*(s: string): TCrc32
|
||||
proc crcFromFile*(filename: string): TCrc32
|
||||
proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
|
||||
# implementation
|
||||
|
||||
type
|
||||
TCRC_TabEntry = int
|
||||
|
||||
const
|
||||
crc32table: array[0..255, TCRC_TabEntry] = [0, 1996959894, - 301047508,
|
||||
- 1727442502, 124634137, 1886057615, - 379345611, - 1637575261, 249268274,
|
||||
2044508324, - 522852066, - 1747789432, 162941995, 2125561021, - 407360249,
|
||||
- 1866523247, 498536548, 1789927666, - 205950648, - 2067906082, 450548861,
|
||||
1843258603, - 187386543, - 2083289657, 325883990, 1684777152, - 43845254,
|
||||
- 1973040660, 335633487, 1661365465, - 99664541, - 1928851979, 997073096,
|
||||
1281953886, - 715111964, - 1570279054, 1006888145, 1258607687, - 770865667,
|
||||
- 1526024853, 901097722, 1119000684, - 608450090, - 1396901568, 853044451,
|
||||
1172266101, - 589951537, - 1412350631, 651767980, 1373503546, - 925412992,
|
||||
- 1076862698, 565507253, 1454621731, - 809855591, - 1195530993, 671266974,
|
||||
1594198024, - 972236366, - 1324619484, 795835527, 1483230225, - 1050600021,
|
||||
- 1234817731, 1994146192, 31158534, - 1731059524, - 271249366, 1907459465,
|
||||
112637215, - 1614814043, - 390540237, 2013776290, 251722036, - 1777751922,
|
||||
- 519137256, 2137656763, 141376813, - 1855689577, - 429695999, 1802195444,
|
||||
476864866, - 2056965928, - 228458418, 1812370925, 453092731, - 2113342271,
|
||||
- 183516073, 1706088902, 314042704, - 1950435094, - 54949764, 1658658271,
|
||||
366619977, - 1932296973, - 69972891, 1303535960, 984961486, - 1547960204,
|
||||
- 725929758, 1256170817, 1037604311, - 1529756563, - 740887301, 1131014506,
|
||||
879679996, - 1385723834, - 631195440, 1141124467, 855842277, - 1442165665,
|
||||
- 586318647, 1342533948, 654459306, - 1106571248, - 921952122, 1466479909,
|
||||
544179635, - 1184443383, - 832445281, 1591671054, 702138776, - 1328506846,
|
||||
- 942167884, 1504918807, 783551873, - 1212326853, - 1061524307, - 306674912,
|
||||
- 1698712650, 62317068, 1957810842, - 355121351, - 1647151185, 81470997,
|
||||
1943803523, - 480048366, - 1805370492, 225274430, 2053790376, - 468791541,
|
||||
- 1828061283, 167816743, 2097651377, - 267414716, - 2029476910, 503444072,
|
||||
1762050814, - 144550051, - 2140837941, 426522225, 1852507879, - 19653770,
|
||||
- 1982649376, 282753626, 1742555852, - 105259153, - 1900089351, 397917763,
|
||||
1622183637, - 690576408, - 1580100738, 953729732, 1340076626, - 776247311,
|
||||
- 1497606297, 1068828381, 1219638859, - 670225446, - 1358292148, 906185462,
|
||||
1090812512, - 547295293, - 1469587627, 829329135, 1181335161, - 882789492,
|
||||
- 1134132454, 628085408, 1382605366, - 871598187, - 1156888829, 570562233,
|
||||
1426400815, - 977650754, - 1296233688, 733239954, 1555261956, - 1026031705,
|
||||
- 1244606671, 752459403, 1541320221, - 1687895376, - 328994266, 1969922972,
|
||||
40735498, - 1677130071, - 351390145, 1913087877, 83908371, - 1782625662,
|
||||
- 491226604, 2075208622, 213261112, - 1831694693, - 438977011, 2094854071,
|
||||
198958881, - 2032938284, - 237706686, 1759359992, 534414190, - 2118248755,
|
||||
- 155638181, 1873836001, 414664567, - 2012718362, - 15766928, 1711684554,
|
||||
285281116, - 1889165569, - 127750551, 1634467795, 376229701, - 1609899400,
|
||||
- 686959890, 1308918612, 956543938, - 1486412191, - 799009033, 1231636301,
|
||||
1047427035, - 1362007478, - 640263460, 1088359270, 936918000, - 1447252397,
|
||||
- 558129467, 1202900863, 817233897, - 1111625188, - 893730166, 1404277552,
|
||||
615818150, - 1160759803, - 841546093, 1423857449, 601450431, - 1285129682,
|
||||
- 1000256840, 1567103746, 711928724, - 1274298825, - 1022587231, 1510334235,
|
||||
755167117]
|
||||
|
||||
proc updateCrc32(val: int8, crc: TCrc32): TCrc32 =
|
||||
result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
|
||||
0x000000FF]) xor (crc shr TCrc32(8))
|
||||
|
||||
proc updateCrc32(val: char, crc: TCrc32): TCrc32 =
|
||||
result = updateCrc32(toU8(ord(val)), crc)
|
||||
|
||||
proc strCrc32(s: string): TCrc32 =
|
||||
result = InitCrc32
|
||||
for i in countup(0, len(s) - 1): result = updateCrc32(s[i], result)
|
||||
|
||||
proc `><`*(c: TCrc32, s: string): TCrc32 =
|
||||
result = c
|
||||
for i in 0..len(s)-1: result = updateCrc32(s[i], result)
|
||||
|
||||
type
|
||||
TByteArray = array[0..10000000, int8]
|
||||
PByteArray = ref TByteArray
|
||||
|
||||
proc crcFromBuf(buf: pointer, length: int): TCrc32 =
|
||||
var p = cast[PByteArray](buf)
|
||||
result = InitCrc32
|
||||
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
|
||||
|
||||
proc crcFromFile(filename: string): TCrc32 =
|
||||
const
|
||||
bufSize = 8000 # don't use 8K for the memory allocator!
|
||||
var
|
||||
bin: File
|
||||
result = InitCrc32
|
||||
if not open(bin, filename):
|
||||
return # not equal if file does not exist
|
||||
var buf = alloc(bufSize)
|
||||
var p = cast[PByteArray](buf)
|
||||
while true:
|
||||
var readBytes = readBuffer(bin, buf, bufSize)
|
||||
for i in countup(0, readBytes - 1): result = updateCrc32(p[i], result)
|
||||
if readBytes != bufSize: break
|
||||
dealloc(buf)
|
||||
close(bin)
|
||||
|
||||
const
|
||||
base = int32(65521) # largest prime smaller than 65536
|
||||
# NMAX = 5552; original code with unsigned 32 bit integer
|
||||
# NMAX is the largest n
|
||||
# such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
nmax = 3854 # code with signed 32 bit integer
|
||||
# NMAX is the largest n such that
|
||||
# 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1
|
||||
# The penalty is the time loss in the extra MOD-calls.
|
||||
|
||||
proc updateAdler32(adler: int32, buf: pointer, length: int): int32 =
|
||||
var
|
||||
s1, s2: int32
|
||||
L, k, b: int
|
||||
s1 = adler and int32(0x0000FFFF)
|
||||
s2 = (adler shr int32(16)) and int32(0x0000FFFF)
|
||||
L = length
|
||||
b = 0
|
||||
while (L > 0):
|
||||
if L < nmax: k = L
|
||||
else: k = nmax
|
||||
dec(L, k)
|
||||
while (k > 0):
|
||||
s1 = s1 +% int32((cast[cstring](buf))[b])
|
||||
s2 = s2 +% s1
|
||||
inc(b)
|
||||
dec(k)
|
||||
s1 = `%%`(s1, base)
|
||||
s2 = `%%`(s2, base)
|
||||
result = (s2 shl int32(16)) or s1
|
||||
|
|
@ -18,7 +18,7 @@ import
|
|||
|
||||
type
|
||||
TSections = array[TSymKind, Rope]
|
||||
TDocumentor = object of rstgen.TRstGenerator
|
||||
TDocumentor = object of rstgen.RstGenerator
|
||||
modDesc: Rope # module description
|
||||
id: int # for generating IDs
|
||||
toc, section: TSections
|
||||
|
|
@ -29,7 +29,7 @@ type
|
|||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
|
||||
msgKind: rst.MsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
var k: msgs.TMsgKind
|
||||
case msgKind
|
||||
|
|
@ -53,7 +53,7 @@ proc docgenFindFile(s: string): string {.procvar.} =
|
|||
|
||||
proc parseRst(text, filename: string,
|
||||
line, column: int, hasToc: var bool,
|
||||
rstOptions: TRstParseOptions): PRstNode =
|
||||
rstOptions: RstParseOptions): PRstNode =
|
||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
|||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
""" % [config["doc.googleAnalytics"]]
|
||||
""" % [config.getOrDefault"doc.googleAnalytics"]
|
||||
else:
|
||||
result.analytics = ""
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ proc genRecComment(d: PDoc, n: PNode): Rope =
|
|||
if n == nil: return nil
|
||||
result = genComment(d, n).rope
|
||||
if result == nil:
|
||||
if n.kind notin {nkEmpty..nkNilLit}:
|
||||
if n.kind notin {nkEmpty..nkNilLit, nkEnumTy}:
|
||||
for i in countup(0, len(n)-1):
|
||||
result = genRecComment(d, n.sons[i])
|
||||
if result != nil: return
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@
|
|||
# This module implements a new documentation generator that runs after
|
||||
# semantic checking.
|
||||
|
||||
import
|
||||
import
|
||||
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen
|
||||
|
||||
type
|
||||
type
|
||||
TGen = object of TPassContext
|
||||
doc: PDoc
|
||||
module: PSym
|
||||
|
|
@ -29,12 +29,12 @@ proc close(p: PPassContext, n: PNode): PNode =
|
|||
except IOError:
|
||||
discard
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
var g = PGen(c)
|
||||
generateDoc(g.doc, n)
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var g: PGen
|
||||
new(g)
|
||||
g.module = module
|
||||
|
|
@ -45,5 +45,5 @@ proc myOpen(module: PSym): PPassContext =
|
|||
|
||||
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
|
||||
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
proc finishDoc2Pass*(project: string) =
|
||||
discard
|
||||
|
|
|
|||
|
|
@ -25,16 +25,21 @@ proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
|||
if ctx.instLines: result.info = b.info
|
||||
|
||||
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
template handleParam(param) =
|
||||
let x = param
|
||||
if x.kind == nkArgList:
|
||||
for y in items(x): result.add(y)
|
||||
else:
|
||||
result.add copyTree(x)
|
||||
|
||||
case templ.kind
|
||||
of nkSym:
|
||||
var s = templ.sym
|
||||
if s.owner.id == c.owner.id:
|
||||
if s.kind == skParam and sfGenSym notin s.flags:
|
||||
let x = actual.sons[s.position]
|
||||
if x.kind == nkArgList:
|
||||
for y in items(x): result.add(y)
|
||||
else:
|
||||
result.add copyTree(x)
|
||||
handleParam actual.sons[s.position]
|
||||
elif s.kind == skGenericParam:
|
||||
handleParam actual.sons[s.owner.typ.len + s.position - 1]
|
||||
else:
|
||||
internalAssert sfGenSym in s.flags
|
||||
var x = PSym(idTableGet(c.mapping, s))
|
||||
|
|
@ -56,20 +61,44 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
|||
proc evalTemplateArgs(n: PNode, s: PSym): PNode =
|
||||
# if the template has zero arguments, it can be called without ``()``
|
||||
# `n` is then a nkSym or something similar
|
||||
var a: int
|
||||
case n.kind
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
a = sonsLen(n)
|
||||
else: a = 0
|
||||
var f = s.typ.sonsLen
|
||||
if a > f: globalError(n.info, errWrongNumberOfArguments)
|
||||
var totalParams = case n.kind
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1
|
||||
else: 0
|
||||
|
||||
var
|
||||
# XXX: Since immediate templates are not subjected to the
|
||||
# standard sigmatching algorithm, they will have a number
|
||||
# of deficiencies when it comes to generic params:
|
||||
# Type dependencies between the parameters won't be honoured
|
||||
# and the bound generic symbols won't be resolvable within
|
||||
# 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
|
||||
else: s.ast[genericParamsPos].len
|
||||
expectedRegularParams = <s.typ.len
|
||||
givenRegularParams = totalParams - genericParams
|
||||
|
||||
if totalParams > expectedRegularParams + genericParams:
|
||||
globalError(n.info, errWrongNumberOfArguments)
|
||||
|
||||
result = newNodeI(nkArgList, n.info)
|
||||
for i in countup(1, f - 1):
|
||||
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
|
||||
if arg == nil or arg.kind == nkEmpty:
|
||||
for i in 1 .. givenRegularParams:
|
||||
result.addSon n.sons[i]
|
||||
|
||||
# handle parameters with default values, which were
|
||||
# not supplied by the user
|
||||
for i in givenRegularParams+1 .. expectedRegularParams:
|
||||
let default = s.typ.n.sons[i].sym.ast
|
||||
if default.isNil or default.kind == nkEmpty:
|
||||
localError(n.info, errWrongNumberOfArguments)
|
||||
addSon(result, arg)
|
||||
addSon(result, ast.emptyNode)
|
||||
else:
|
||||
addSon(result, default.copyTree)
|
||||
|
||||
# add any generic paramaters
|
||||
for i in 1 .. genericParams:
|
||||
result.addSon n.sons[givenRegularParams + i]
|
||||
|
||||
var evalTemplateCounter* = 0
|
||||
# to prevent endless recursion in templates instantiation
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@
|
|||
# nim files.
|
||||
|
||||
import
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
securehash, streams
|
||||
|
||||
type
|
||||
TSystemCC* = enum
|
||||
ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
|
||||
ccTcc, ccPcc, ccUcc, ccIcl
|
||||
ccTcc, ccPcc, ccUcc, ccIcl, asmFasm
|
||||
TInfoCCProp* = enum # properties of the C compiler:
|
||||
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
|
||||
hasComputedGoto, # CC has computed goto (GNU C extension)
|
||||
|
|
@ -26,8 +27,8 @@ type
|
|||
hasAssume, # CC has __assume (Visual C extension)
|
||||
hasGcGuard, # CC supports GC_GUARD to keep stack roots
|
||||
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
|
||||
hasNakedDeclspec, # CC has __declspec(naked)
|
||||
hasNakedAttribute # CC has __attribute__((naked))
|
||||
hasDeclspec, # CC has __declspec(X)
|
||||
hasAttribute, # CC has __attribute__((X))
|
||||
TInfoCCProps* = set[TInfoCCProp]
|
||||
TInfoCC* = tuple[
|
||||
name: string, # the short name of the compiler
|
||||
|
|
@ -85,7 +86,7 @@ compiler gcc:
|
|||
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
||||
packedPragma: "__attribute__((__packed__))",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasNakedAttribute})
|
||||
hasAttribute})
|
||||
|
||||
# LLVM Frontend for GCC/G++
|
||||
compiler llvmGcc:
|
||||
|
|
@ -122,12 +123,12 @@ compiler vcc:
|
|||
includeCmd: " /I",
|
||||
linkDirCmd: " /LIBPATH:",
|
||||
linkLibCmd: " $1.lib",
|
||||
debug: " /GZ /Zi ",
|
||||
debug: " /RTC1 /Z7 ",
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$3$n$1 $2",
|
||||
packedPragma: "#pragma pack(1)",
|
||||
props: {hasCpp, hasAssume, hasNakedDeclspec})
|
||||
props: {hasCpp, hasAssume, hasDeclspec})
|
||||
|
||||
# Intel C/C++ Compiler
|
||||
compiler icl:
|
||||
|
|
@ -317,6 +318,31 @@ compiler ucc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
# fasm assembler
|
||||
compiler fasm:
|
||||
result = (
|
||||
name: "fasm",
|
||||
objExt: "o",
|
||||
optSpeed: "",
|
||||
optSize: "",
|
||||
compilerExe: "fasm",
|
||||
cppCompiler: "fasm",
|
||||
compileTmpl: "$file $objfile",
|
||||
buildGui: "",
|
||||
buildDll: "",
|
||||
buildLib: "",
|
||||
linkerExe: "",
|
||||
linkTmpl: "",
|
||||
includeCmd: "",
|
||||
linkDirCmd: "",
|
||||
linkLibCmd: "",
|
||||
debug: "",
|
||||
pic: "",
|
||||
asmStmtFrmt: "",
|
||||
structStmtFmt: "",
|
||||
packedPragma: "",
|
||||
props: {})
|
||||
|
||||
const
|
||||
CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
|
||||
gcc(),
|
||||
|
|
@ -330,17 +356,22 @@ const
|
|||
tcc(),
|
||||
pcc(),
|
||||
ucc(),
|
||||
icl()]
|
||||
icl(),
|
||||
fasm()]
|
||||
|
||||
hExt* = ".h"
|
||||
|
||||
var
|
||||
cCompiler* = ccGcc # the used compiler
|
||||
cAssembler* = ccNone
|
||||
gMixedMode*: bool # true if some module triggered C++ codegen
|
||||
cIncludes*: seq[string] = @[] # directories to search for included files
|
||||
cLibs*: seq[string] = @[] # directories to search for lib files
|
||||
cLinkedLibs*: seq[string] = @[] # libraries to link
|
||||
|
||||
const
|
||||
cValidAssemblers* = {asmFasm}
|
||||
|
||||
# implementation
|
||||
|
||||
proc libNameTmpl(): string {.inline.} =
|
||||
|
|
@ -428,7 +459,7 @@ proc resetCompilationLists* =
|
|||
initLinkedList(toCompile)
|
||||
## XXX: we must associate these with their originating module
|
||||
# when the module is loaded/unloaded it adds/removes its items
|
||||
# That's because we still need to CRC check the external files
|
||||
# That's because we still need to hash check the external files
|
||||
# Maybe we can do that in checkDep on the other hand?
|
||||
initLinkedList(externalToCompile)
|
||||
initLinkedList(toLink)
|
||||
|
|
@ -437,17 +468,13 @@ proc addFileToLink*(filename: string) =
|
|||
prependStr(toLink, filename)
|
||||
# BUGFIX: was ``appendStr``
|
||||
|
||||
proc execWithEcho(cmd: string, prettyCmd = ""): int =
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0:
|
||||
if prettyCmd != "":
|
||||
msgWriteln(prettyCmd)
|
||||
else:
|
||||
msgWriteln(cmd)
|
||||
proc execWithEcho(cmd: string, msg = hintExecuting): int =
|
||||
rawMessage(msg, cmd)
|
||||
result = execCmd(cmd)
|
||||
|
||||
proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||
if execWithEcho(cmd, prettyCmd) != 0:
|
||||
rawMessage(errExecutionOfProgramFailed, "")
|
||||
proc execExternalProgram*(cmd: string, msg = hintExecuting) =
|
||||
if execWithEcho(cmd, msg) != 0:
|
||||
rawMessage(errExecutionOfProgramFailed, cmd)
|
||||
|
||||
proc generateScript(projectFile: string, script: Rope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
|
|
@ -530,6 +557,21 @@ proc getLinkerExe(compiler: TSystemCC): string =
|
|||
|
||||
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
var c = cCompiler
|
||||
if cfilename.endswith(".asm"):
|
||||
var customAssembler = getConfigVar("assembler")
|
||||
if customAssembler.len > 0:
|
||||
c = nameToCC(customAssembler)
|
||||
else:
|
||||
if targetCPU == cpuI386 or targetCPU == cpuAmd64:
|
||||
c = asmFasm
|
||||
else:
|
||||
c = ccNone
|
||||
|
||||
if c == ccNone:
|
||||
rawMessage(errExternalAssemblerNotFound, "")
|
||||
elif c notin cValidAssemblers:
|
||||
rawMessage(errExternalAssemblerNotValid, customAssembler)
|
||||
|
||||
var options = cFileSpecificOptions(cfilename)
|
||||
var exe = getConfigVar(c, ".exe")
|
||||
if exe.len == 0: exe = c.getCompilerExe
|
||||
|
|
@ -572,32 +614,30 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
|||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
|
||||
proc footprint(filename: string): TCrc32 =
|
||||
# note, '><' further modifies a crc value with a string.
|
||||
result = crcFromFile(filename) ><
|
||||
platform.OS[targetOS].name ><
|
||||
platform.CPU[targetCPU].name ><
|
||||
extccomp.CC[extccomp.cCompiler].name ><
|
||||
getCompileCFileCmd(filename, true)
|
||||
proc footprint(filename: string): SecureHash =
|
||||
result = secureHash(
|
||||
$secureHashFile(filename) &
|
||||
platform.OS[targetOS].name &
|
||||
platform.CPU[targetCPU].name &
|
||||
extccomp.CC[extccomp.cCompiler].name &
|
||||
getCompileCFileCmd(filename, true))
|
||||
|
||||
proc externalFileChanged(filename: string): bool =
|
||||
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||
return false
|
||||
|
||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||
var currentCrc = int(footprint(filename))
|
||||
var hashFile = toGeneratedFile(filename.withPackageName, "sha1")
|
||||
var currentHash = footprint(filename)
|
||||
var f: File
|
||||
if open(f, crcFile, fmRead):
|
||||
var line = newStringOfCap(40)
|
||||
if not f.readLine(line): line = "0"
|
||||
if open(f, hashFile, fmRead):
|
||||
let oldHash = parseSecureHash(f.readLine())
|
||||
close(f)
|
||||
var oldCrc = parseInt(line)
|
||||
result = oldCrc != currentCrc
|
||||
result = oldHash != currentHash
|
||||
else:
|
||||
result = true
|
||||
if result:
|
||||
if open(f, crcFile, fmWrite):
|
||||
f.writeln($currentCrc)
|
||||
if open(f, hashFile, fmWrite):
|
||||
f.writeLine($currentHash)
|
||||
close(f)
|
||||
|
||||
proc addExternalFileToCompile*(filename: string) =
|
||||
|
|
@ -632,6 +672,12 @@ proc callCCompiler*(projectfile: string) =
|
|||
var prettyCmds: TStringSeq = @[]
|
||||
let prettyCb = proc (idx: int) =
|
||||
echo prettyCmds[idx]
|
||||
let runCb = proc (idx: int, p: Process) =
|
||||
let exitCode = p.peekExitCode
|
||||
if exitCode != 0:
|
||||
rawMessage(errGenerated, "execution of an external compiler program '" &
|
||||
cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
|
||||
p.outputStream.readAll.strip)
|
||||
compileCFile(toCompile, script, cmds, prettyCmds, false)
|
||||
compileCFile(externalToCompile, script, cmds, prettyCmds, true)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
|
|
@ -640,22 +686,19 @@ proc callCCompiler*(projectfile: string) =
|
|||
if gNumberOfProcessors <= 1:
|
||||
for i in countup(0, high(cmds)):
|
||||
res = execWithEcho(cmds[i])
|
||||
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
||||
if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
|
||||
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||
res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams},
|
||||
gNumberOfProcessors, afterRunEvent=runCb)
|
||||
elif gVerbosity == 1:
|
||||
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||
gNumberOfProcessors, prettyCb)
|
||||
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
|
||||
gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
|
||||
else:
|
||||
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
|
||||
gNumberOfProcessors, afterRunEvent=runCb)
|
||||
if res != 0:
|
||||
if gNumberOfProcessors <= 1:
|
||||
rawMessage(errExecutionOfProgramFailed, [])
|
||||
else:
|
||||
rawMessage(errGenerated, " execution of an external program failed; " &
|
||||
"rerun with --parallelBuild:1 to see the error message")
|
||||
rawMessage(errExecutionOfProgramFailed, cmds.join())
|
||||
if optNoLinking notin gGlobalOptions:
|
||||
# call the linker:
|
||||
var it = PStrEntry(toLink.head)
|
||||
|
|
@ -668,7 +711,8 @@ proc callCCompiler*(projectfile: string) =
|
|||
it = PStrEntry(it.next)
|
||||
|
||||
if optGenStaticLib in gGlobalOptions:
|
||||
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
||||
let name = splitFile(gProjectName).name
|
||||
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name),
|
||||
"objfiles", objfiles]
|
||||
else:
|
||||
var linkerExe = getConfigVar(c, ".linkerexe")
|
||||
|
|
@ -703,10 +747,8 @@ proc callCCompiler*(projectfile: string) =
|
|||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if gVerbosity == 1:
|
||||
execExternalProgram(linkCmd, "[Linking]")
|
||||
else:
|
||||
execExternalProgram(linkCmd)
|
||||
execExternalProgram(linkCmd,
|
||||
if gVerbosity > 1: hintExecuting else: hintLinking)
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
|
|
|
|||
|
|
@ -9,18 +9,18 @@
|
|||
|
||||
# This module implements Nim's standard template filter.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer, filters
|
||||
|
||||
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream
|
||||
# #! template(subsChar='$', metaChar='#') | standard(version="0.7.2")
|
||||
# implementation
|
||||
|
||||
type
|
||||
TParseState = enum
|
||||
type
|
||||
TParseState = enum
|
||||
psDirective, psTempl
|
||||
TTmplParser{.final.} = object
|
||||
TTmplParser{.final.} = object
|
||||
inp: PLLStream
|
||||
state: TParseState
|
||||
info: TLineInfo
|
||||
|
|
@ -33,18 +33,18 @@ type
|
|||
pendingExprLine: bool
|
||||
|
||||
|
||||
const
|
||||
const
|
||||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||
|
||||
proc newLine(p: var TTmplParser) =
|
||||
proc newLine(p: var TTmplParser) =
|
||||
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||
p.emitPar = 0
|
||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||
if p.pendingExprLine:
|
||||
llStreamWrite(p.outp, spaces(2))
|
||||
p.pendingExprLine = false
|
||||
|
||||
proc scanPar(p: var TTmplParser, d: int) =
|
||||
|
||||
proc scanPar(p: var TTmplParser, d: int) =
|
||||
var i = d
|
||||
while true:
|
||||
case p.x[i]
|
||||
|
|
@ -58,44 +58,44 @@ proc scanPar(p: var TTmplParser, d: int) =
|
|||
else: discard
|
||||
inc(i)
|
||||
|
||||
proc withInExpr(p: TTmplParser): bool {.inline.} =
|
||||
proc withInExpr(p: TTmplParser): bool {.inline.} =
|
||||
result = p.par > 0 or p.bracket > 0 or p.curly > 0
|
||||
|
||||
proc parseLine(p: var TTmplParser) =
|
||||
var
|
||||
|
||||
proc parseLine(p: var TTmplParser) =
|
||||
var
|
||||
d, j, curly: int
|
||||
keyw: string
|
||||
j = 0
|
||||
while p.x[j] == ' ': inc(j)
|
||||
if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'):
|
||||
if p.x[0] == p.nimDirective and p.x[1] in {'?', '!'}:
|
||||
newLine(p)
|
||||
elif (p.x[j] == p.nimDirective):
|
||||
elif p.x[j] == p.nimDirective:
|
||||
newLine(p)
|
||||
inc(j)
|
||||
while p.x[j] == ' ': inc(j)
|
||||
d = j
|
||||
keyw = ""
|
||||
while p.x[j] in PatternChars:
|
||||
while p.x[j] in PatternChars:
|
||||
add(keyw, p.x[j])
|
||||
inc(j)
|
||||
|
||||
|
||||
scanPar(p, j)
|
||||
p.pendingExprLine = withInExpr(p) or llstream.endsWithOpr(p.x)
|
||||
case whichKeyword(keyw)
|
||||
of wEnd:
|
||||
if p.indent >= 2:
|
||||
of wEnd:
|
||||
if p.indent >= 2:
|
||||
dec(p.indent, 2)
|
||||
else:
|
||||
else:
|
||||
p.info.col = int16(j)
|
||||
localError(p.info, errXNotAllowedHere, "end")
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, "#end")
|
||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||
wConverter, wMacro, wTemplate, wMethod:
|
||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||
wConverter, wMacro, wTemplate, wMethod:
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
inc(p.indent, 2)
|
||||
of wElif, wOf, wElse, wExcept, wFinally:
|
||||
of wElif, wOf, wElse, wExcept, wFinally:
|
||||
llStreamWrite(p.outp, spaces(p.indent - 2))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
of wLet, wVar, wConst, wType:
|
||||
|
|
@ -108,7 +108,7 @@ proc parseLine(p: var TTmplParser) =
|
|||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
p.state = psDirective
|
||||
else:
|
||||
else:
|
||||
# data line
|
||||
# reset counters
|
||||
p.par = 0
|
||||
|
|
@ -116,42 +116,42 @@ proc parseLine(p: var TTmplParser) =
|
|||
p.bracket = 0
|
||||
j = 0
|
||||
case p.state
|
||||
of psTempl:
|
||||
of psTempl:
|
||||
# next line of string literal:
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, "\n")
|
||||
llStreamWrite(p.outp, spaces(p.indent + 2))
|
||||
llStreamWrite(p.outp, "\"")
|
||||
of psDirective:
|
||||
of psDirective:
|
||||
newLine(p)
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, p.emit)
|
||||
llStreamWrite(p.outp, "(\"")
|
||||
inc(p.emitPar)
|
||||
p.state = psTempl
|
||||
while true:
|
||||
while true:
|
||||
case p.x[j]
|
||||
of '\0':
|
||||
break
|
||||
of '\x01'..'\x1F', '\x80'..'\xFF':
|
||||
of '\0':
|
||||
break
|
||||
of '\x01'..'\x1F', '\x80'..'\xFF':
|
||||
llStreamWrite(p.outp, "\\x")
|
||||
llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
|
||||
inc(j)
|
||||
of '\\':
|
||||
of '\\':
|
||||
llStreamWrite(p.outp, "\\\\")
|
||||
inc(j)
|
||||
of '\'':
|
||||
of '\'':
|
||||
llStreamWrite(p.outp, "\\\'")
|
||||
inc(j)
|
||||
of '\"':
|
||||
of '\"':
|
||||
llStreamWrite(p.outp, "\\\"")
|
||||
inc(j)
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
# parse Nim expression:
|
||||
inc(j)
|
||||
case p.x[j]
|
||||
of '{':
|
||||
of '{':
|
||||
p.info.col = int16(j)
|
||||
llStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
|
|
@ -159,50 +159,50 @@ proc parseLine(p: var TTmplParser) =
|
|||
llStreamWrite(p.outp, '(')
|
||||
inc(j)
|
||||
curly = 0
|
||||
while true:
|
||||
while true:
|
||||
case p.x[j]
|
||||
of '\0':
|
||||
of '\0':
|
||||
localError(p.info, errXExpected, "}")
|
||||
break
|
||||
of '{':
|
||||
of '{':
|
||||
inc(j)
|
||||
inc(curly)
|
||||
llStreamWrite(p.outp, '{')
|
||||
of '}':
|
||||
of '}':
|
||||
inc(j)
|
||||
if curly == 0: break
|
||||
if curly == 0: break
|
||||
if curly > 0: dec(curly)
|
||||
llStreamWrite(p.outp, '}')
|
||||
else:
|
||||
else:
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
llStreamWrite(p.outp, ')')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, '\"')
|
||||
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
|
||||
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
|
||||
llStreamWrite(p.outp, '\"')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, p.toStr)
|
||||
llStreamWrite(p.outp, '(')
|
||||
while p.x[j] in PatternChars:
|
||||
while p.x[j] in PatternChars:
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
llStreamWrite(p.outp, ')')
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, '\"')
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
llStreamWrite(p.outp, p.subsChar)
|
||||
inc(j)
|
||||
else:
|
||||
else:
|
||||
p.info.col = int16(j)
|
||||
localError(p.info, errInvalidExpression, "$")
|
||||
else:
|
||||
else:
|
||||
llStreamWrite(p.outp, p.x[j])
|
||||
inc(j)
|
||||
llStreamWrite(p.outp, "\\n\"")
|
||||
|
||||
proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var p: TTmplParser
|
||||
p.info = newLineInfo(filename, 0, 0)
|
||||
p.outp = llStreamOpen("")
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
# This module implements Nim's simple filters and helpers for filters.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
renderer
|
||||
|
||||
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
|
||||
|
|
@ -21,40 +21,40 @@ proc strArg*(n: PNode, name: string, pos: int, default: string): string
|
|||
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
|
||||
# implementation
|
||||
|
||||
proc invalidPragma(n: PNode) =
|
||||
proc invalidPragma(n: PNode) =
|
||||
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc getArg(n: PNode, name: string, pos: int): PNode =
|
||||
proc getArg(n: PNode, name: string, pos: int): PNode =
|
||||
result = nil
|
||||
if n.kind in {nkEmpty..nkNilLit}: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
if n.kind in {nkEmpty..nkNilLit}: return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
|
||||
if identEq(n.sons[i].sons[0].ident, name):
|
||||
if identEq(n.sons[i].sons[0].ident, name):
|
||||
return n.sons[i].sons[1]
|
||||
elif i == pos:
|
||||
elif i == pos:
|
||||
return n.sons[i]
|
||||
|
||||
proc charArg(n: PNode, name: string, pos: int, default: char): char =
|
||||
|
||||
proc charArg(n: PNode, name: string, pos: int, default: char): char =
|
||||
var x = getArg(n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind == nkCharLit: result = chr(int(x.intVal))
|
||||
else: invalidPragma(n)
|
||||
|
||||
proc strArg(n: PNode, name: string, pos: int, default: string): string =
|
||||
|
||||
proc strArg(n: PNode, name: string, pos: int, default: string): string =
|
||||
var x = getArg(n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
|
||||
else: invalidPragma(n)
|
||||
|
||||
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
|
||||
|
||||
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
|
||||
var x = getArg(n, name, pos)
|
||||
if x == nil: result = default
|
||||
elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
|
||||
elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
|
||||
else: invalidPragma(n)
|
||||
|
||||
proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
|
||||
proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var pattern = strArg(call, "startswith", 1, "")
|
||||
var leading = boolArg(call, "leading", 2, true)
|
||||
var trailing = boolArg(call, "trailing", 3, true)
|
||||
|
|
@ -62,13 +62,13 @@ proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
|||
var line = newStringOfCap(80)
|
||||
while llStreamReadLine(stdin, line):
|
||||
var stripped = strip(line, leading, trailing)
|
||||
if (len(pattern) == 0) or startsWith(stripped, pattern):
|
||||
if (len(pattern) == 0) or startsWith(stripped, pattern):
|
||||
llStreamWriteln(result, stripped)
|
||||
else:
|
||||
else:
|
||||
llStreamWriteln(result, line)
|
||||
llStreamClose(stdin)
|
||||
|
||||
proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||
var sub = strArg(call, "sub", 1, "")
|
||||
if len(sub) == 0: invalidPragma(call)
|
||||
var by = strArg(call, "by", 2, "")
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
import ast, astalgo
|
||||
|
||||
const
|
||||
someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
someCmp = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
mLeCh, mLeB, mLePtr, mLtI, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
mLtCh, mLtB, mLtPtr}
|
||||
|
||||
proc isCounter(s: PSym): bool {.inline.} =
|
||||
s.kind in {skResult, skVar, skLet, skTemp} and
|
||||
s.kind in {skResult, skVar, skLet, skTemp} and
|
||||
{sfGlobal, sfAddrTaken} * s.flags == {}
|
||||
|
||||
proc isCall(n: PNode): bool {.inline.} =
|
||||
|
|
@ -29,7 +29,7 @@ proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
|||
proc getCounter(lastStmt: PNode): PSym =
|
||||
if lastStmt.isCall:
|
||||
let op = lastStmt.sym
|
||||
if op.magic in {mDec, mInc} or
|
||||
if op.magic in {mDec, mInc} or
|
||||
((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
|
||||
if op[1].kind == nkSym and isCounter(op[1].sym):
|
||||
result = op[1].sym
|
||||
|
|
@ -67,7 +67,7 @@ proc extractForLoop*(loop, fullTree: PNode): ForLoop =
|
|||
|
||||
if not cond.isCall: return
|
||||
if cond[0].sym.magic notin someCmp: return
|
||||
|
||||
|
||||
var lastStmt = loop[1]
|
||||
while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
|
||||
lastStmt = lastStmt.lastSon
|
||||
|
|
@ -76,7 +76,7 @@ proc extractForLoop*(loop, fullTree: PNode): ForLoop =
|
|||
if counter.isNil or counter.ast.isNil: return
|
||||
|
||||
template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
|
||||
|
||||
|
||||
if cond[1] =~ counter or cond[2] =~ counter:
|
||||
# ok, now check 'counter' is not used *after* the loop
|
||||
if counterInTree(fullTree, loop, counter): return
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
|
|||
saturate
|
||||
|
||||
const
|
||||
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
|
||||
|
||||
# set excluded here as the semantics are vastly different:
|
||||
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
someLe = {mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
mLeCh, mLeB, mLePtr, mLeStr}
|
||||
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
someLt = {mLtI, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
mLtCh, mLtB, mLtPtr, mLtStr}
|
||||
|
||||
someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
|
||||
|
|
@ -30,13 +30,14 @@ const
|
|||
someHigh = {mHigh}
|
||||
# we don't list unsigned here because wrap around semantics suck for
|
||||
# proving anything:
|
||||
someAdd = {mAddI, mAddI64, mAddF64, mSucc}
|
||||
someSub = {mSubI, mSubI64, mSubF64, mPred}
|
||||
someMul = {mMulI, mMulI64, mMulF64}
|
||||
someDiv = {mDivI, mDivI64, mDivF64}
|
||||
someMod = {mModI, mModI64}
|
||||
someAdd = {mAddI, mAddF64, mSucc}
|
||||
someSub = {mSubI, mSubF64, mPred}
|
||||
someMul = {mMulI, mMulF64}
|
||||
someDiv = {mDivI, mDivF64}
|
||||
someMod = {mModI}
|
||||
someMax = {mMaxI, mMaxF64}
|
||||
someMin = {mMinI, mMinF64}
|
||||
someBinaryOp = someAdd+someSub+someMul+someMax+someMin
|
||||
|
||||
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
|
||||
proc isLocation(n: PNode): bool = not n.isValue
|
||||
|
|
@ -165,11 +166,21 @@ proc `|+|`(a, b: PNode): PNode =
|
|||
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |+| b.intVal
|
||||
else: result.floatVal = a.floatVal + b.floatVal
|
||||
|
||||
proc `|-|`(a, b: PNode): PNode =
|
||||
result = copyNode(a)
|
||||
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |-| b.intVal
|
||||
else: result.floatVal = a.floatVal - b.floatVal
|
||||
|
||||
proc `|*|`(a, b: PNode): PNode =
|
||||
result = copyNode(a)
|
||||
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |*| b.intVal
|
||||
else: result.floatVal = a.floatVal * b.floatVal
|
||||
|
||||
proc `|div|`(a, b: PNode): PNode =
|
||||
result = copyNode(a)
|
||||
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal
|
||||
else: result.floatVal = a.floatVal / b.floatVal
|
||||
|
||||
proc negate(a, b, res: PNode): PNode =
|
||||
if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
|
||||
var b = copyNode(b)
|
||||
|
|
@ -213,10 +224,16 @@ proc reassociation(n: PNode): PNode =
|
|||
if result[2].isValue and
|
||||
result[1].getMagic in someAdd and result[1][2].isValue:
|
||||
result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
|
||||
if result[2].intVal == 0:
|
||||
result = result[1]
|
||||
of someMul:
|
||||
if result[2].isValue and
|
||||
result[1].getMagic in someMul and result[1][2].isValue:
|
||||
result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
|
||||
result = opMul.buildCall(result[1][1], result[1][2] |*| result[2])
|
||||
if result[2].intVal == 1:
|
||||
result = result[1]
|
||||
elif result[2].intVal == 0:
|
||||
result = zero()
|
||||
else: discard
|
||||
|
||||
proc pred(n: PNode): PNode =
|
||||
|
|
@ -234,7 +251,7 @@ proc canon*(n: PNode): PNode =
|
|||
result.sons[i] = canon(n.sons[i])
|
||||
elif n.kind == nkSym and n.sym.kind == skLet and
|
||||
n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
|
||||
someMax + someHigh + {mUnaryLt} + someSub + someLen):
|
||||
someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv):
|
||||
result = n.sym.ast.copyTree
|
||||
else:
|
||||
result = n
|
||||
|
|
@ -248,7 +265,7 @@ proc canon*(n: PNode): PNode =
|
|||
# high == len+(-1)
|
||||
result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
|
||||
of mUnaryLt:
|
||||
result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
|
||||
result = buildCall(opAdd, result[1], minusOne())
|
||||
of someSub:
|
||||
# x - 4 --> x + (-4)
|
||||
result = negate(result[1], result[2], result)
|
||||
|
|
@ -294,6 +311,16 @@ proc canon*(n: PNode): PNode =
|
|||
if plus != nil and not isLetLocation(x, true):
|
||||
result = buildCall(result[0].sym, plus, y[1])
|
||||
else: discard
|
||||
elif x.isValue and y.getMagic in someAdd and y[2].isValue:
|
||||
# 0 <= a.len + 3
|
||||
# -3 <= a.len
|
||||
result.sons[1] = x |-| y[2]
|
||||
result.sons[2] = y[1]
|
||||
elif x.isValue and y.getMagic in someSub and y[2].isValue:
|
||||
# 0 <= a.len - 3
|
||||
# 3 <= a.len
|
||||
result.sons[1] = x |+| y[2]
|
||||
result.sons[2] = y[1]
|
||||
else: discard
|
||||
|
||||
proc `+@`*(a: PNode; b: BiggestInt): PNode =
|
||||
|
|
@ -313,6 +340,9 @@ proc usefulFact(n: PNode): PNode =
|
|||
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
|
||||
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
|
||||
result = n
|
||||
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
|
||||
# XXX Rethink this whole idea of 'usefulFact' for semparallel
|
||||
result = n
|
||||
of mIsNil:
|
||||
if isLetLocation(n.sons[1], false) or isVar(n.sons[1]):
|
||||
result = n
|
||||
|
|
@ -366,8 +396,8 @@ proc usefulFact(n: PNode): PNode =
|
|||
type
|
||||
TModel* = seq[PNode] # the "knowledge base"
|
||||
|
||||
proc addFact*(m: var TModel, n: PNode) =
|
||||
let n = usefulFact(n)
|
||||
proc addFact*(m: var TModel, nn: PNode) =
|
||||
let n = usefulFact(nn)
|
||||
if n != nil: m.add n
|
||||
|
||||
proc addFactNeg*(m: var TModel, n: PNode) =
|
||||
|
|
@ -697,10 +727,57 @@ proc simpleSlice*(a, b: PNode): BiggestInt =
|
|||
else:
|
||||
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
|
||||
|
||||
import macros
|
||||
|
||||
macro `=~`(x: PNode, pat: untyped): bool =
|
||||
proc m(x, pat, conds: NimNode) =
|
||||
case pat.kind
|
||||
of nnkInfix:
|
||||
case $pat[0]
|
||||
of "*": conds.add getAst(isMul(x))
|
||||
of "/": conds.add getAst(isDiv(x))
|
||||
of "+": conds.add getAst(isAdd(x))
|
||||
of "-": conds.add getAst(isSub(x))
|
||||
else:
|
||||
error("invalid pattern")
|
||||
m(newTree(nnkBracketExpr, x, newLit(1)), pat[1], conds)
|
||||
m(newTree(nnkBracketExpr, x, newLit(2)), pat[2], conds)
|
||||
of nnkPar:
|
||||
if pat.len == 1:
|
||||
m(x, pat[0], conds)
|
||||
else:
|
||||
error("invalid pattern")
|
||||
of nnkIdent:
|
||||
let c = newTree(nnkStmtListExpr, newLetStmt(pat, x))
|
||||
conds.add c
|
||||
if ($pat)[^1] == 'c': c.add(getAst(isVal(pat)))
|
||||
else: c.add bindSym"true"
|
||||
of nnkIntLit:
|
||||
conds.add(getAst(isIntVal(pat.intVal)))
|
||||
else:
|
||||
error("invalid pattern")
|
||||
|
||||
var conds = newTree(nnkBracket)
|
||||
m(x, pat, conds)
|
||||
result = nestList(!"and", conds)
|
||||
|
||||
|
||||
proc isMinusOne(n: PNode): bool =
|
||||
n.kind in {nkCharLit..nkUInt64Lit} and n.intVal == -1
|
||||
|
||||
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
|
||||
|
||||
# 0 <= 3
|
||||
if a.isValue and b.isValue:
|
||||
|
|
@ -721,6 +798,7 @@ proc ple(m: TModel; a, b: PNode): TImplication =
|
|||
if a.intVal <= 0: return impYes
|
||||
|
||||
# x <= y+c if 0 <= c and x <= y
|
||||
# x <= y+(-c) if c <= 0 and y >= x
|
||||
if b.getMagic in someAdd and zero() <=? b[2] and a <=? b[1]: return impYes
|
||||
|
||||
# x+c <= y if c <= 0 and x <= y
|
||||
|
|
@ -730,10 +808,44 @@ proc ple(m: TModel; a, b: PNode): TImplication =
|
|||
if b.getMagic in someMul:
|
||||
if a <=? b[1] and one() <=? b[2] and zero() <=? b[1]: return impYes
|
||||
|
||||
|
||||
if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and
|
||||
a[1][2].isValue:
|
||||
# simplify (x div 4) * 2 <= y to x div (c div d) <= y
|
||||
if ple(m, buildCall(opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
|
||||
return impYes
|
||||
|
||||
# x*3 + x == x*4. It follows that:
|
||||
# x*3 + y <= x*4 if y <= x and 3 <= 4
|
||||
if a =~ x*dc + y and b =~ x2*ec:
|
||||
if sameTree(x, x2):
|
||||
let ec1 = opAdd.buildCall(ec, minusOne())
|
||||
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x:
|
||||
return impYes
|
||||
elif a =~ x*dc and b =~ x2*ec + y:
|
||||
#echo "BUG cam ehrer e ", a, " <=? ", b
|
||||
if sameTree(x, x2):
|
||||
let ec1 = opAdd.buildCall(ec, minusOne())
|
||||
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero():
|
||||
return impYes
|
||||
|
||||
# x+c <= x+d if c <= d. Same for *, - etc.
|
||||
if a.getMagic in someBinaryOp and a.getMagic == b.getMagic:
|
||||
if sameTree(a[1], b[1]) and a[2] <=? b[2]: return impYes
|
||||
elif sameTree(a[2], b[2]) and a[1] <=? b[1]: return impYes
|
||||
|
||||
# x div c <= y if 1 <= c and 0 <= y and x <= y:
|
||||
if a.getMagic in someDiv:
|
||||
if one() <=? a[2] and zero() <=? b and a[1] <=? b: return impYes
|
||||
|
||||
# x div c <= x div d if d <= c
|
||||
if b.getMagic in someDiv:
|
||||
if sameTree(a[1], b[1]) and b[2] <=? a[2]: return impYes
|
||||
|
||||
# x div z <= x - 1 if z <= x
|
||||
if a[2].isValue and b.getMagic in someAdd and b[2].isMinusOne:
|
||||
if a[2] <=? a[1] and sameTree(a[1], b[1]): return impYes
|
||||
|
||||
# slightly subtle:
|
||||
# x <= max(y, z) iff x <= y or x <= z
|
||||
# note that 'x <= max(x, z)' is a special case of the above rule
|
||||
|
|
@ -769,11 +881,19 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
|
|||
for i in 0..m.high:
|
||||
let fact = m[i]
|
||||
if fact != nil and fact.getMagic in someLe:
|
||||
# x <= y implies a <= b if a <= x and y <= b
|
||||
let x = fact[1]
|
||||
let y = fact[2]
|
||||
# mark as used:
|
||||
m[i] = nil
|
||||
# i <= len-100
|
||||
# i <=? len-1
|
||||
# --> true if (len-100) <= (len-1)
|
||||
let x = fact[1]
|
||||
let y = fact[2]
|
||||
if sameTree(x, a) and y.getMagic in someAdd and b.getMagic in someAdd and
|
||||
sameTree(y[1], b[1]):
|
||||
if ple(m, b[2], y[2]) == impYes:
|
||||
return impYes
|
||||
|
||||
# x <= y implies a <= b if a <= x and y <= b
|
||||
if ple(m, a, x) == impYes:
|
||||
if ple(m, y, b) == impYes:
|
||||
return impYes
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
|||
else:
|
||||
result = semDirectOp(c, n, {})
|
||||
if optHints in gOptions and hintPattern in gNotes:
|
||||
message(orig.info, hintPattern, rule & " --> '" &
|
||||
message(orig.info, hintPattern, rule & " --> '" &
|
||||
renderTree(result, {renderNoComments}) & "'")
|
||||
|
||||
proc applyPatterns(c: PContext, n: PNode): PNode =
|
||||
|
|
@ -68,7 +68,7 @@ proc hlo(c: PContext, n: PNode): PNode =
|
|||
result = n
|
||||
else:
|
||||
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
|
||||
n.sons[0].kind == nkSym and
|
||||
n.sons[0].kind == nkSym and
|
||||
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
|
||||
# do not optimize 'var g {.global} = re(...)' again!
|
||||
return n
|
||||
|
|
|
|||
|
|
@ -11,19 +11,19 @@
|
|||
# An identifier is a shared immutable string that can be compared by its
|
||||
# id. This module is essential for the compiler's performance.
|
||||
|
||||
import
|
||||
hashes, strutils
|
||||
import
|
||||
hashes, strutils, etcpriv
|
||||
|
||||
type
|
||||
type
|
||||
TIdObj* = object of RootObj
|
||||
id*: int # unique id; use this for comparisons and not the pointers
|
||||
|
||||
|
||||
PIdObj* = ref TIdObj
|
||||
PIdent* = ref TIdent
|
||||
TIdent*{.acyclic.} = object of TIdObj
|
||||
s*: string
|
||||
next*: PIdent # for hash-table chaining
|
||||
h*: THash # hash value of s
|
||||
h*: Hash # hash value of s
|
||||
|
||||
var firstCharIsCS*: bool = true
|
||||
var buckets*: array[0..4096 * 2 - 1, PIdent]
|
||||
|
|
@ -37,18 +37,20 @@ proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
|
|||
while j < blen:
|
||||
while a[i] == '_': inc(i)
|
||||
while b[j] == '_': inc(j)
|
||||
while isMagicIdentSeparatorRune(a, i): inc(i, magicIdentSeparatorRuneByteWidth)
|
||||
while isMagicIdentSeparatorRune(b, j): inc(j, magicIdentSeparatorRuneByteWidth)
|
||||
# tolower inlined:
|
||||
var aa = a[i]
|
||||
var bb = b[j]
|
||||
if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A')))
|
||||
if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A')))
|
||||
result = ord(aa) - ord(bb)
|
||||
if (result != 0) or (aa == '\0'): break
|
||||
if (result != 0) or (aa == '\0'): break
|
||||
inc(i)
|
||||
inc(j)
|
||||
if result == 0:
|
||||
if a[i] != '\0': result = 1
|
||||
|
||||
|
||||
proc cmpExact(a, b: cstring, blen: int): int =
|
||||
var i = 0
|
||||
var j = 0
|
||||
|
|
@ -57,27 +59,27 @@ proc cmpExact(a, b: cstring, blen: int): int =
|
|||
var aa = a[i]
|
||||
var bb = b[j]
|
||||
result = ord(aa) - ord(bb)
|
||||
if (result != 0) or (aa == '\0'): break
|
||||
if (result != 0) or (aa == '\0'): break
|
||||
inc(i)
|
||||
inc(j)
|
||||
if result == 0:
|
||||
if result == 0:
|
||||
if a[i] != '\0': result = 1
|
||||
|
||||
var wordCounter = 1
|
||||
|
||||
proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
|
||||
proc getIdent*(identifier: cstring, length: int, h: Hash): PIdent =
|
||||
var idx = h and high(buckets)
|
||||
result = buckets[idx]
|
||||
var last: PIdent = nil
|
||||
var id = 0
|
||||
while result != nil:
|
||||
if cmpExact(cstring(result.s), identifier, length) == 0:
|
||||
if last != nil:
|
||||
while result != nil:
|
||||
if cmpExact(cstring(result.s), identifier, length) == 0:
|
||||
if last != nil:
|
||||
# make access to last looked up identifier faster:
|
||||
last.next = result.next
|
||||
result.next = buckets[idx]
|
||||
buckets[idx] = result
|
||||
return
|
||||
return
|
||||
elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
|
||||
assert((id == 0) or (id == result.id))
|
||||
id = result.id
|
||||
|
|
@ -89,20 +91,20 @@ proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
|
|||
for i in countup(0, length - 1): result.s[i] = identifier[i]
|
||||
result.next = buckets[idx]
|
||||
buckets[idx] = result
|
||||
if id == 0:
|
||||
if id == 0:
|
||||
inc(wordCounter)
|
||||
result.id = -wordCounter
|
||||
else:
|
||||
else:
|
||||
result.id = id
|
||||
|
||||
proc getIdent*(identifier: string): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier),
|
||||
proc getIdent*(identifier: string): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier),
|
||||
hashIgnoreStyle(identifier))
|
||||
|
||||
proc getIdent*(identifier: string, h: THash): PIdent =
|
||||
proc getIdent*(identifier: string, h: Hash): PIdent =
|
||||
result = getIdent(cstring(identifier), len(identifier), h)
|
||||
|
||||
proc identEq*(id: PIdent, name: string): bool =
|
||||
proc identEq*(id: PIdent, name: string): bool =
|
||||
result = id.id == getIdent(name).id
|
||||
|
||||
var idAnon* = getIdent":anonymous"
|
||||
|
|
|
|||
|
|
@ -18,26 +18,26 @@ const
|
|||
|
||||
when debugIds:
|
||||
import intsets
|
||||
|
||||
|
||||
var usedIds = initIntSet()
|
||||
|
||||
proc registerID*(id: PIdObj) =
|
||||
when debugIds:
|
||||
if id.id == -1 or containsOrIncl(usedIds, id.id):
|
||||
proc registerID*(id: PIdObj) =
|
||||
when debugIds:
|
||||
if id.id == -1 or containsOrIncl(usedIds, id.id):
|
||||
internalError("ID already used: " & $id.id)
|
||||
|
||||
proc getID*(): int {.inline.} =
|
||||
proc getID*(): int {.inline.} =
|
||||
result = gFrontEndId
|
||||
inc(gFrontEndId)
|
||||
|
||||
proc backendId*(): int {.inline.} =
|
||||
proc backendId*(): int {.inline.} =
|
||||
result = gBackendId
|
||||
inc(gBackendId)
|
||||
|
||||
proc setId*(id: int) {.inline.} =
|
||||
proc setId*(id: int) {.inline.} =
|
||||
gFrontEndId = max(gFrontEndId, id + 1)
|
||||
|
||||
proc idSynchronizationPoint*(idRange: int) =
|
||||
proc idSynchronizationPoint*(idRange: int) =
|
||||
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
|
||||
|
||||
proc toGid(f: string): string =
|
||||
|
|
@ -48,10 +48,10 @@ proc toGid(f: string): string =
|
|||
|
||||
proc saveMaxIds*(project: string) =
|
||||
var f = open(project.toGid, fmWrite)
|
||||
f.writeln($gFrontEndId)
|
||||
f.writeln($gBackendId)
|
||||
f.writeLine($gFrontEndId)
|
||||
f.writeLine($gBackendId)
|
||||
f.close()
|
||||
|
||||
|
||||
proc loadMaxIds*(project: string) =
|
||||
var f: File
|
||||
if open(f, project.toGid, fmRead):
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
|||
if s.kind != skEnumField:
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
if exceptSet.empty or s.name.id notin exceptSet:
|
||||
if exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
s = nextIter(i, fromMod.tab)
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
|||
let s = a.sym
|
||||
if s.kind == skModule:
|
||||
importAllSymbolsExcept(c, s, exceptSet)
|
||||
elif exceptSet.empty or s.name.id notin exceptSet:
|
||||
elif exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
of nkExportExceptStmt:
|
||||
localError(n.info, errGenerated, "'export except' not implemented")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Name: "Nim"
|
|||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
linux: i386;amd64;powerpc64;arm;sparc;mips;powerpc
|
||||
linux: i386;amd64;powerpc64;arm;sparc;mips;mipsel;powerpc;powerpc64el;arm64
|
||||
macosx: i386;amd64;powerpc64
|
||||
solaris: i386;amd64;sparc
|
||||
freebsd: i386;amd64
|
||||
|
|
@ -99,9 +99,13 @@ 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/wrappers/readline/*.nim"
|
||||
Files: "lib/wrappers/linenoise/*.nim"
|
||||
Files: "lib/wrappers/linenoise/*.c"
|
||||
Files: "lib/wrappers/linenoise/*.h"
|
||||
Files: "lib/wrappers/sdl/*.nim"
|
||||
Files: "lib/wrappers/zip/*.nim"
|
||||
Files: "lib/wrappers/zip/libzip_all.c"
|
||||
|
|
@ -111,6 +115,9 @@ Files: "lib/posix/*.nim"
|
|||
Files: "lib/js/*.nim"
|
||||
Files: "lib/packages/docutils/*.nim"
|
||||
|
||||
Files: "lib/deprecated/core/*.nim"
|
||||
Files: "lib/deprecated/pure/*.nim"
|
||||
Files: "lib/deprecated/pure/*.cfg"
|
||||
|
||||
[Other]
|
||||
Files: "examples/*.nim"
|
||||
|
|
@ -203,7 +210,11 @@ Files: "tests/stdlib/*.nim"
|
|||
Files: "tests/system/*.nim"
|
||||
Files: "tests/template/*.nim"
|
||||
Files: "tests/testament/*.nim"
|
||||
Files: "tests/testdata/*.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"
|
||||
|
|
@ -236,6 +247,7 @@ BinPath: r"bin;dist\mingw\bin;dist"
|
|||
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
|
||||
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"
|
||||
; for now only NSIS supports optional downloads
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ implements the required case distinction.
|
|||
|
||||
|
||||
import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
|
||||
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, os,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
||||
intsets, cgmeth, lowerings
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
|||
result = etyBaseIndex
|
||||
of tyPointer:
|
||||
# treat a tyPointer like a typed pointer to an array of bytes
|
||||
result = etyInt
|
||||
result = etyBaseIndex
|
||||
of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
|
||||
result = mapType(t.sons[0])
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
|
||||
|
|
@ -197,10 +197,10 @@ proc isSimpleExpr(n: PNode): bool =
|
|||
elif n.isAtom:
|
||||
result = true
|
||||
|
||||
proc getTemp(p: PProc): Rope =
|
||||
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||
inc(p.unique)
|
||||
result = "Tmp$1" % [rope(p.unique)]
|
||||
addf(p.locals, "var $1;$n" | "local $1;$n", [result])
|
||||
if defineInLocals: addf(p.locals, "var $1;$n" | "local $1;$n", [result])
|
||||
|
||||
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
assert r.kind == resNone
|
||||
|
|
@ -258,11 +258,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
|
||||
["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
|
||||
["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
|
||||
["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
|
||||
["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
|
||||
["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
|
||||
["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
|
||||
["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
|
||||
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
|
||||
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
|
||||
["", "", "($1 + $2)", "($1 + $2)"], # AddF64
|
||||
|
|
@ -276,11 +271,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
|
||||
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
|
||||
["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
|
||||
["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
|
||||
["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
|
||||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
|
||||
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
|
||||
|
|
@ -291,9 +281,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["", "", "($1 == $2)", "($1 == $2)"], # EqI
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtI
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqI64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtI64
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqF64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtF64
|
||||
|
|
@ -320,11 +307,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
|
||||
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
|
||||
["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
|
||||
["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
|
||||
["", "", "!($1)", "!($1)"], # Not
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusI
|
||||
["", "", "~($1)", "~($1)"], # BitnotI
|
||||
["", "", "~($1)", "~($1)"], # BitnotI64
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusF64
|
||||
["", "", "-($1)", "-($1)"], # UnaryMinusF64
|
||||
["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
|
||||
|
|
@ -357,11 +342,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
|
||||
["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
|
||||
["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
|
||||
["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
|
||||
["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
|
||||
["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
|
||||
["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
|
||||
["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
|
||||
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
|
||||
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
|
||||
["", "", "($1 + $2)", "($1 + $2)"], # AddF64
|
||||
|
|
@ -375,11 +355,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
|
||||
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
|
||||
["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
|
||||
["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
|
||||
["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
|
||||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
|
||||
["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
|
||||
["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
|
||||
["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
|
||||
|
|
@ -390,9 +365,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["", "", "($1 == $2)", "($1 == $2)"], # EqI
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtI
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqI64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtI64
|
||||
["", "", "($1 == $2)", "($1 == $2)"], # EqF64
|
||||
["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
|
||||
["", "", "($1 < $2)", "($1 < $2)"], # LtF64
|
||||
|
|
@ -419,11 +391,9 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
|||
["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
|
||||
["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
|
||||
["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
|
||||
["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
|
||||
["", "", "not ($1)", "not ($1)"], # Not
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusI
|
||||
["", "", "~($1)", "~($1)"], # BitnotI
|
||||
["", "", "~($1)", "~($1)"], # BitnotI64
|
||||
["", "", "+($1)", "+($1)"], # UnaryPlusF64
|
||||
["", "", "-($1)", "-($1)"], # UnaryMinusF64
|
||||
["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
|
||||
|
|
@ -535,12 +505,12 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
|||
proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# code to generate:
|
||||
#
|
||||
# var sp = {prev: excHandler, exc: null};
|
||||
# excHandler = sp;
|
||||
# ++excHandler;
|
||||
# try {
|
||||
# stmts;
|
||||
# TMP = e
|
||||
# } catch (e) {
|
||||
# } catch (EXC) {
|
||||
# var prevJSError = lastJSError; lastJSError = EXC;
|
||||
# --excHandler;
|
||||
# if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
|
||||
# stmts;
|
||||
# } else if (e.typ && e.typ == NTI32342) {
|
||||
|
|
@ -548,35 +518,41 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
# } else {
|
||||
# stmts;
|
||||
# }
|
||||
# lastJSError = prevJSError;
|
||||
# } finally {
|
||||
# stmts;
|
||||
# excHandler = excHandler.prev;
|
||||
# }
|
||||
genLineDir(p, n)
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
r.res = getTemp(p)
|
||||
inc(p.unique)
|
||||
var i = 1
|
||||
var length = sonsLen(n)
|
||||
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
|
||||
if catchBranchesExist:
|
||||
add(p.body, "++excHandler;" & tnl)
|
||||
var safePoint = "Tmp$1" % [rope(p.unique)]
|
||||
addf(p.body,
|
||||
"var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
|
||||
"" |
|
||||
"local $1 = pcall(",
|
||||
[safePoint])
|
||||
if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
|
||||
addf(p.body, "try {$n" | "function()$n", [])
|
||||
var length = sonsLen(n)
|
||||
var a: TCompRes
|
||||
gen(p, n.sons[0], a)
|
||||
moveInto(p, a, r)
|
||||
var i = 1
|
||||
if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
|
||||
addf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n", [])
|
||||
var generalCatchBranchExists = false
|
||||
if p.target == targetJS and catchBranchesExist:
|
||||
addf(p.body, "} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||
elif p.target == targetLua:
|
||||
addf(p.body, "end)$n", [])
|
||||
while i < length and n.sons[i].kind == nkExceptBranch:
|
||||
let blen = sonsLen(n.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
generalCatchBranchExists = true
|
||||
if i > 1: addf(p.body, "else {$n" | "else$n", [])
|
||||
gen(p, n.sons[i].sons[0], a)
|
||||
moveInto(p, a, r)
|
||||
|
|
@ -588,17 +564,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if n.sons[i].sons[j].kind != nkType:
|
||||
internalError(n.info, "genTryStmt")
|
||||
if orExpr != nil: add(orExpr, "||" | " or ")
|
||||
addf(orExpr, "isObj($1.exc.m_type, $2)",
|
||||
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
|
||||
addf(orExpr, "isObj(lastJSError.m_type, $1)",
|
||||
[genTypeInfo(p, n.sons[i].sons[j].typ)])
|
||||
if i > 1: add(p.body, "else ")
|
||||
addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
|
||||
addf(p.body, "if (lastJSError && ($2)) {$n" | "if $1.exc and ($2) then$n",
|
||||
[safePoint, orExpr])
|
||||
gen(p, n.sons[i].sons[blen - 1], a)
|
||||
moveInto(p, a, r)
|
||||
addf(p.body, "}$n" | "end$n", [])
|
||||
inc(i)
|
||||
if p.target == targetJS:
|
||||
add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
|
||||
if catchBranchesExist:
|
||||
if not generalCatchBranchExists:
|
||||
useMagic(p, "reraiseException")
|
||||
add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl)
|
||||
add(p.body, "lastJSError = prevJSError;" & tnl)
|
||||
add(p.body, "} finally {" & tnl)
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
genStmt(p, n.sons[i].sons[0])
|
||||
if p.target == targetJS:
|
||||
|
|
@ -748,14 +729,13 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
|||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||
addf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [rope(p.blocks[idx].id)])
|
||||
|
||||
proc genAsmStmt(p: PProc, n: PNode) =
|
||||
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||
genLineDir(p, n)
|
||||
assert(n.kind == nkAsmStmt)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
|
||||
of nkSym: add(p.body, mangleName(n.sons[i].sym))
|
||||
else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
|
||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||
|
||||
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var cond, stmt: TCompRes
|
||||
|
|
@ -810,19 +790,36 @@ proc needsNoCopy(y: PNode): bool =
|
|||
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
var a, b: TCompRes
|
||||
gen(p, x, a)
|
||||
|
||||
let xtyp = mapType(x.typ)
|
||||
|
||||
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
||||
gen(p, x.sons[0], a)
|
||||
let tmp = p.getTemp(false)
|
||||
addf(p.body, "var $1 = $2;$n", [tmp, a.rdLoc])
|
||||
a.res = "$1[0][$1[1]]" % [tmp]
|
||||
else:
|
||||
gen(p, x, a)
|
||||
|
||||
gen(p, y, b)
|
||||
case mapType(x.typ)
|
||||
|
||||
case xtyp
|
||||
of etyObject:
|
||||
if needsNoCopy(y) or noCopyNeeded:
|
||||
if (needsNoCopy(y) and needsNoCopy(x)) or noCopyNeeded:
|
||||
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "$1 = nimCopy($2, $3);$n",
|
||||
addf(p.body, "nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyBaseIndex:
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
internalError(x.info, "genAsgn")
|
||||
addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
if y.kind == nkCall:
|
||||
let tmp = p.getTemp(false)
|
||||
addf(p.body, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
|
||||
else:
|
||||
internalError(x.info, "genAsgn")
|
||||
else:
|
||||
addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||
else:
|
||||
addf(p.body, "$1 = $2;$n", [a.res, b.res])
|
||||
|
||||
|
|
@ -838,11 +835,9 @@ proc genSwap(p: PProc, n: PNode) =
|
|||
var a, b: TCompRes
|
||||
gen(p, n.sons[1], a)
|
||||
gen(p, n.sons[2], b)
|
||||
inc(p.unique)
|
||||
var tmp = "Tmp$1" % [rope(p.unique)]
|
||||
var tmp = p.getTemp(false)
|
||||
if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
|
||||
inc(p.unique)
|
||||
let tmp2 = "Tmp$1" % [rope(p.unique)]
|
||||
let tmp2 = p.getTemp(false)
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
internalError(n.info, "genSwap")
|
||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||
|
|
@ -880,7 +875,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
|
||||
r.res = "$1.Field$2" % [r.res, getFieldPosition(n.sons[1]).rope]
|
||||
else:
|
||||
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAddr")
|
||||
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
||||
var f = n.sons[1].sym
|
||||
if f.loc.r == nil: f.loc.r = mangleName(f)
|
||||
r.res = "$1.$2" % [r.res, f.loc.r]
|
||||
|
|
@ -970,18 +965,35 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
of nkCheckedFieldExpr:
|
||||
genCheckedFieldAddr(p, n, r)
|
||||
of nkDotExpr:
|
||||
genFieldAddr(p, n.sons[0], r)
|
||||
if mapType(n.typ) == etyBaseIndex:
|
||||
genFieldAddr(p, n.sons[0], r)
|
||||
else:
|
||||
genFieldAccess(p, n.sons[0], r)
|
||||
of nkBracketExpr:
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
||||
case ty.kind
|
||||
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
|
||||
tyVarargs, tyChar:
|
||||
genArrayAddr(p, n.sons[0], r)
|
||||
of tyTuple:
|
||||
genFieldAddr(p, n.sons[0], r)
|
||||
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
else: internalError(n.sons[0].info, "genAddr")
|
||||
if ty.kind in MappedToObject:
|
||||
gen(p, n.sons[0], r)
|
||||
else:
|
||||
let kindOfIndexedExpr = skipTypes(n.sons[0].sons[0].typ, abstractVarRange).kind
|
||||
case kindOfIndexedExpr
|
||||
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
|
||||
tyVarargs:
|
||||
genArrayAddr(p, n.sons[0], r)
|
||||
of tyTuple:
|
||||
genFieldAddr(p, n.sons[0], r)
|
||||
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
||||
of nkObjDownConv:
|
||||
gen(p, n.sons[0], r)
|
||||
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
||||
|
||||
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
let newp = genProc(p, s)
|
||||
var owner = p
|
||||
while owner != nil and owner.prc != s.owner:
|
||||
owner = owner.up
|
||||
if owner != nil: add(owner.locals, newp)
|
||||
else: add(p.g.code, newp)
|
||||
|
||||
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var s = n.sym
|
||||
|
|
@ -1018,13 +1030,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
|||
discard
|
||||
elif sfForward in s.flags:
|
||||
p.g.forwarded.add(s)
|
||||
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
let newp = genProc(p, s)
|
||||
var owner = p
|
||||
while owner != nil and owner.prc != s.owner:
|
||||
owner = owner.up
|
||||
if owner != nil: add(owner.locals, newp)
|
||||
else: add(p.g.code, newp)
|
||||
else:
|
||||
genProcForSymIfNeeded(p, s)
|
||||
else:
|
||||
if s.loc.r == nil:
|
||||
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||
|
|
@ -1037,10 +1044,15 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
|
|||
else:
|
||||
var a: TCompRes
|
||||
gen(p, n.sons[0], a)
|
||||
if a.typ != etyBaseIndex: internalError(n.info, "genDeref")
|
||||
r.res = "$1[$2]" % [a.address, a.res]
|
||||
if a.typ == etyBaseIndex:
|
||||
r.res = "$1[$2]" % [a.address, a.res]
|
||||
elif n.sons[0].kind == nkCall:
|
||||
let tmp = p.getTemp
|
||||
r.res = "($1 = $2, $1[0][$1[1]])" % [tmp, a.res]
|
||||
else:
|
||||
internalError(n.info, "genDeref")
|
||||
|
||||
proc genArg(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
gen(p, n, a)
|
||||
if a.typ == etyBaseIndex:
|
||||
|
|
@ -1050,13 +1062,42 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) =
|
|||
else:
|
||||
add(r.res, a.res)
|
||||
|
||||
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
gen(p, n, a)
|
||||
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
|
||||
a.typ == etyBaseIndex:
|
||||
add(r.res, "$1[$2]" % [a.address, a.res])
|
||||
elif a.typ == etyBaseIndex:
|
||||
add(r.res, a.address)
|
||||
add(r.res, ", ")
|
||||
add(r.res, a.res)
|
||||
else:
|
||||
add(r.res, a.res)
|
||||
|
||||
|
||||
proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||
add(r.res, "(")
|
||||
var hasArgs = false
|
||||
|
||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
if it.typ.isCompileTimeOnly: continue
|
||||
if i > 1: add(r.res, ", ")
|
||||
genArg(p, it, r)
|
||||
var paramType : PNode = nil
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
paramType = typ.n.sons[i]
|
||||
if paramType.typ.isCompileTimeOnly: continue
|
||||
|
||||
if hasArgs: add(r.res, ", ")
|
||||
if paramType.isNil:
|
||||
genArgNoParam(p, it, r)
|
||||
else:
|
||||
genArg(p, it, paramType.sym, r)
|
||||
hasArgs = true
|
||||
add(r.res, ")")
|
||||
r.kind = resExpr
|
||||
|
||||
|
|
@ -1080,11 +1121,12 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
|||
add(r.res, "(")
|
||||
for i in countup(2, sonsLen(n) - 1):
|
||||
if i > 2: add(r.res, ", ")
|
||||
genArg(p, n.sons[i], r)
|
||||
genArgNoParam(p, n.sons[i], r)
|
||||
add(r.res, ")")
|
||||
r.kind = resExpr
|
||||
|
||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "toJSStr") # Used in rawEcho
|
||||
useMagic(p, "rawEcho")
|
||||
add(r.res, "rawEcho(")
|
||||
let n = n[1].skipConv
|
||||
|
|
@ -1093,7 +1135,7 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
|||
let it = n.sons[i]
|
||||
if it.typ.isCompileTimeOnly: continue
|
||||
if i > 0: add(r.res, ", ")
|
||||
genArg(p, it, r)
|
||||
genArgNoParam(p, it, r)
|
||||
add(r.res, ")")
|
||||
r.kind = resExpr
|
||||
|
||||
|
|
@ -1102,24 +1144,32 @@ proc putToSeq(s: string, indirect: bool): Rope =
|
|||
if indirect: result = "[$1]" % [result]
|
||||
|
||||
proc createVar(p: PProc, typ: PType, indirect: bool): Rope
|
||||
proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope =
|
||||
result = nil
|
||||
proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) =
|
||||
case rec.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(rec) - 1):
|
||||
add(result, createRecordVarAux(p, rec.sons[i], c))
|
||||
createRecordVarAux(p, rec.sons[i], excludedFieldIDs, output)
|
||||
of nkRecCase:
|
||||
add(result, createRecordVarAux(p, rec.sons[0], c))
|
||||
createRecordVarAux(p, rec.sons[0], excludedFieldIDs, output)
|
||||
for i in countup(1, sonsLen(rec) - 1):
|
||||
add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
|
||||
createRecordVarAux(p, lastSon(rec.sons[i]), excludedFieldIDs, output)
|
||||
of nkSym:
|
||||
if c > 0: add(result, ", ")
|
||||
add(result, mangleName(rec.sym))
|
||||
add(result, ": ")
|
||||
add(result, createVar(p, rec.sym.typ, false))
|
||||
inc(c)
|
||||
if rec.sym.id notin excludedFieldIDs:
|
||||
if output.len > 0: output.add(", ")
|
||||
output.add(mangleName(rec.sym))
|
||||
output.add(": ")
|
||||
output.add(createVar(p, rec.sym.typ, false))
|
||||
else: internalError(rec.info, "createRecordVarAux")
|
||||
|
||||
proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
|
||||
var t = typ
|
||||
if tfFinal notin t.flags or t.sons[0] != nil:
|
||||
if output.len > 0: output.add(", ")
|
||||
addf(output, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
|
||||
while t != nil:
|
||||
createRecordVarAux(p, t.n, excludedFieldIDs, output)
|
||||
t = t.sons[0]
|
||||
|
||||
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
|
|
@ -1160,15 +1210,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
|||
add(result, "}")
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyObject:
|
||||
result = rope("{")
|
||||
var c = 0
|
||||
if tfFinal notin t.flags or t.sons[0] != nil:
|
||||
inc(c)
|
||||
addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
|
||||
while t != nil:
|
||||
add(result, createRecordVarAux(p, t.n, c))
|
||||
t = t.sons[0]
|
||||
add(result, "}")
|
||||
var initList : Rope
|
||||
createObjInitList(p, t, initIntSet(), initList)
|
||||
result = "{$1}" % [initList]
|
||||
if indirect: result = "[$1]" % [result]
|
||||
of tyVar, tyPtr, tyRef:
|
||||
if mapType(t) == etyBaseIndex:
|
||||
|
|
@ -1197,7 +1241,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
|||
s = a.res
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
s = "nimCopy($1, $2)" % [a.res, genTypeInfo(p, n.typ)]
|
||||
s = "nimCopy(null, $1, $2)" % [a.res, genTypeInfo(p, n.typ)]
|
||||
of etyBaseIndex:
|
||||
if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
|
||||
if {sfAddrTaken, sfGlobal} * v.flags != {}:
|
||||
|
|
@ -1389,6 +1433,12 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
|||
of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
||||
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
||||
of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
||||
of mDotDot:
|
||||
genProcForSymIfNeeded(p, n.sons[0].sym)
|
||||
genCall(p, n, r)
|
||||
of mParseBiggestFloat:
|
||||
useMagic(p, "nimParseBiggestFloat")
|
||||
genCall(p, n, r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
||||
|
|
@ -1434,19 +1484,22 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
r.res.add("}")
|
||||
|
||||
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
# XXX inheritance?
|
||||
var a: TCompRes
|
||||
r.res = rope("{")
|
||||
r.kind = resExpr
|
||||
var initList : Rope
|
||||
var fieldIDs = initIntSet()
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i > 1: add(r.res, ", ")
|
||||
if i > 1: add(initList, ", ")
|
||||
var it = n.sons[i]
|
||||
internalAssert it.kind == nkExprColonExpr
|
||||
gen(p, it.sons[1], a)
|
||||
var f = it.sons[0].sym
|
||||
if f.loc.r == nil: f.loc.r = mangleName(f)
|
||||
addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
|
||||
r.res.add("}")
|
||||
fieldIDs.incl(f.id)
|
||||
addf(initList, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
|
||||
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
||||
createObjInitList(p, t, fieldIDs, initList)
|
||||
r.res = "{$1}" % [initList]
|
||||
|
||||
proc genConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var dest = skipTypes(n.typ, abstractVarRange)
|
||||
|
|
@ -1551,7 +1604,10 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
|||
mangleName(resultSym),
|
||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||
gen(p, prc.ast.sons[resultPos], a)
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
if mapType(resultSym.typ) == etyBaseIndex:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
genStmt(p, prc.getBody)
|
||||
result = ("function $#($#) {$n$#$#$#$#}$n" |
|
||||
"function $#($#) $n$#$#$#$#$nend$n") %
|
||||
|
|
@ -1565,6 +1621,12 @@ proc genStmt(p: PProc, n: PNode) =
|
|||
gen(p, n, r)
|
||||
if r.res != nil: addf(p.body, "$#;$n", [r.res])
|
||||
|
||||
proc genPragma(p: PProc, n: PNode) =
|
||||
for it in n.sons:
|
||||
case whichPragma(it)
|
||||
of wEmit: genAsmOrEmitStmt(p, it.sons[1])
|
||||
else: discard
|
||||
|
||||
proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.typ = etyNone
|
||||
r.kind = resNone
|
||||
|
|
@ -1648,6 +1710,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
|||
gen(p, lastSon(n), r)
|
||||
of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
|
||||
of nkIfStmt, nkIfExpr: genIf(p, n, r)
|
||||
of nkWhen:
|
||||
# This is "when nimvm" node
|
||||
gen(p, n.sons[1].sons[0], r)
|
||||
of nkWhileStmt: genWhileStmt(p, n)
|
||||
of nkVarSection, nkLetSection: genVarStmt(p, n)
|
||||
of nkConstSection: discard
|
||||
|
|
@ -1664,12 +1729,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if n.sons[0].kind != nkEmpty:
|
||||
genLineDir(p, n)
|
||||
gen(p, n.sons[0], r)
|
||||
of nkAsmStmt: genAsmStmt(p, n)
|
||||
of nkAsmStmt: genAsmOrEmitStmt(p, n)
|
||||
of nkTryStmt: genTry(p, n, r)
|
||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef: discard
|
||||
of nkPragma: genPragma(p, n)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
var s = n.sons[namePos].sym
|
||||
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
|
||||
|
|
@ -1691,7 +1757,7 @@ proc genHeader(): Rope =
|
|||
result = ("/* Generated by the Nim Compiler v$1 */$n" &
|
||||
"/* (c) 2015 Andreas Rumpf */$n$n" &
|
||||
"var framePtr = null;$n" &
|
||||
"var excHandler = null;$n" &
|
||||
"var excHandler = 0;$n" &
|
||||
"var lastJSError = null;$n") %
|
||||
[rope(VersionAsString)]
|
||||
|
||||
|
|
|
|||
|
|
@ -116,13 +116,12 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
|
|||
[name, genTypeInfo(p, typ.sons[0])])
|
||||
|
||||
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||
var t = typ
|
||||
if t.kind == tyGenericInst: t = lastSon(t)
|
||||
let t = typ.skipTypes({tyGenericInst})
|
||||
result = "NTI$1" % [rope(t.id)]
|
||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||
case t.kind
|
||||
of tyDistinct:
|
||||
result = genTypeInfo(p, typ.sons[0])
|
||||
result = genTypeInfo(p, t.sons[0])
|
||||
of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
|
||||
var s =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
|
|
@ -134,14 +133,14 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
|
|||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.lastSon)])
|
||||
[result, genTypeInfo(p, t.lastSon)])
|
||||
of tyArrayConstr, tyArray:
|
||||
var s =
|
||||
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
|
||||
[result, rope(ord(t.kind))]
|
||||
prepend(p.g.typeInfo, s)
|
||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||
[result, genTypeInfo(p, typ.sons[1])])
|
||||
[result, genTypeInfo(p, t.sons[1])])
|
||||
of tyEnum: genEnumInfo(p, t, result)
|
||||
of tyObject: genObjectInfo(p, t, result)
|
||||
of tyTuple: genTupleInfo(p, t, result)
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
|
|||
var params = routine.ast.sons[paramsPos]
|
||||
# -1 is correct here as param.position is 0 based but we have at position 0
|
||||
# some nkEffect node:
|
||||
param.position = params.len-1
|
||||
param.position = routine.typ.n.len-1
|
||||
addSon(params, newSymNode(param))
|
||||
incl(routine.typ.flags, tfCapturesEnv)
|
||||
assert sfFromGeneric in param.flags
|
||||
|
|
@ -859,11 +859,17 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
|||
return indirectAccess(newSymNode(it.closureParam), local, n.info)
|
||||
|
||||
if local.kind == skClosureIterator:
|
||||
# bug #3354; allow for
|
||||
#iterator iter(): int {.closure.}=
|
||||
# s.add(iter)
|
||||
# yield 1
|
||||
|
||||
#if local == o.fn or local == it.fn:
|
||||
# message(n.info, errRecursiveDependencyX, local.name.s)
|
||||
|
||||
# consider: [i1, i2, i1] Since we merged the iterator's closure
|
||||
# with the captured owning variables, we need to generate the
|
||||
# closure generation code again:
|
||||
if local == o.fn or local == it.fn:
|
||||
message(n.info, errRecursiveDependencyX, local.name.s)
|
||||
# XXX why doesn't this work?
|
||||
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
|
||||
if closure.isNil:
|
||||
|
|
@ -946,7 +952,11 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
|||
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS or
|
||||
|
||||
# However we can do lifting for the stuff which is *only* compiletime.
|
||||
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
||||
|
||||
if body.kind == nkEmpty or (gCmd == cmdCompileToJS and not isCompileTime) or
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
|
|
@ -1012,7 +1022,9 @@ proc liftForLoop*(body: PNode): PNode =
|
|||
...
|
||||
"""
|
||||
var L = body.len
|
||||
internalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
|
||||
if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
|
||||
localError(body.info, "ignored invalid for loop")
|
||||
return body
|
||||
var call = body[L-2]
|
||||
|
||||
result = newNodeI(nkStmtList, body.info)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import
|
||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
||||
wordrecg
|
||||
wordrecg, etcpriv
|
||||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
|
|
@ -140,10 +140,12 @@ proc isKeyword*(kind: TTokType): bool =
|
|||
proc isNimIdentifier*(s: string): bool =
|
||||
if s[0] in SymStartChars:
|
||||
var i = 1
|
||||
while i < s.len:
|
||||
var sLen = s.len
|
||||
while i < sLen:
|
||||
if s[i] == '_':
|
||||
inc(i)
|
||||
if s[i] notin SymChars: return
|
||||
elif isMagicIdentSeparatorRune(cstring s, i):
|
||||
inc(i, magicIdentSeparatorRuneByteWidth)
|
||||
if s[i] notin SymChars: return
|
||||
inc(i)
|
||||
result = true
|
||||
|
|
@ -229,23 +231,6 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
|||
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
|
||||
L.dispMessage(info, msg, arg)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
if buf[pos+1] notin chars:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
add(tok.literal, '_')
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||
|
||||
|
|
@ -268,136 +253,200 @@ proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
|||
result = i - start
|
||||
{.pop.} # overflowChecks
|
||||
|
||||
|
||||
template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
|
||||
add(t.literal, replacementChar)
|
||||
inc(L.bufpos)
|
||||
|
||||
template eatChar(L: var TLexer, t: var TToken) =
|
||||
add(t.literal, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
|
||||
proc getNumber(L: var TLexer): TToken =
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
if buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
else:
|
||||
break
|
||||
if buf[pos] == '_':
|
||||
if buf[pos+1] notin chars:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
add(tok.literal, '_')
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while buf[pos] in chars:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) =
|
||||
# Used to get slightly human friendlier err messages.
|
||||
# Note: the erroneous 'O' char in the character set is intentional
|
||||
const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
|
||||
'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'}
|
||||
var msgPos = L.bufpos
|
||||
var t: TToken
|
||||
t.literal = ""
|
||||
L.bufpos = startpos # Use L.bufpos as pos because of matchChars
|
||||
matchChars(L, t, literalishChars)
|
||||
# We must verify +/- specifically so that we're not past the literal
|
||||
if L.buf[L.bufpos] in {'+', '-'} and
|
||||
L.buf[L.bufpos - 1] in {'e', 'E'}:
|
||||
add(t.literal, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
matchChars(L, t, literalishChars)
|
||||
if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
|
||||
inc(L.bufpos)
|
||||
add(t.literal, L.buf[L.bufpos])
|
||||
matchChars(L, t, {'0'..'9'})
|
||||
L.bufpos = msgPos
|
||||
lexMessage(L, msg, t.literal)
|
||||
|
||||
var
|
||||
pos, endpos: int
|
||||
startpos, endpos: int
|
||||
xi: BiggestInt
|
||||
# get the base:
|
||||
isBase10 = true
|
||||
const
|
||||
baseCodeChars = {'X', 'x', 'o', 'c', 'C', 'b', 'B'}
|
||||
literalishChars = baseCodeChars + {'A'..'F', 'a'..'f', '0'..'9', '_', '\''}
|
||||
floatTypes = {tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit}
|
||||
result.tokType = tkIntLit # int literal until we know better
|
||||
result.literal = ""
|
||||
result.base = base10 # BUGFIX
|
||||
pos = L.bufpos # make sure the literal is correct for error messages:
|
||||
var eallowed = false
|
||||
if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
|
||||
matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
|
||||
result.base = base10
|
||||
startpos = L.bufpos
|
||||
|
||||
# First stage: find out base, make verifications, build token literal string
|
||||
if L.buf[L.bufpos] == '0' and L.buf[L.bufpos + 1] in baseCodeChars + {'O'}:
|
||||
isBase10 = false
|
||||
eatChar(L, result, '0')
|
||||
case L.buf[L.bufpos]
|
||||
of 'O':
|
||||
lexMessageLitNum(L, errInvalidNumberOctalCode, startpos)
|
||||
of 'x', 'X':
|
||||
eatChar(L, result, 'x')
|
||||
matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
|
||||
of 'o', 'c', 'C':
|
||||
eatChar(L, result, 'c')
|
||||
matchUnderscoreChars(L, result, {'0'..'7'})
|
||||
of 'b', 'B':
|
||||
eatChar(L, result, 'b')
|
||||
matchUnderscoreChars(L, result, {'0'..'1'})
|
||||
else:
|
||||
internalError(getLineInfo(L), "getNumber")
|
||||
else:
|
||||
matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
|
||||
eallowed = true
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
add(result.literal, '.')
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
eallowed = true
|
||||
if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
|
||||
add(result.literal, 'e')
|
||||
inc(L.bufpos)
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
add(result.literal, L.buf[L.bufpos])
|
||||
inc(L.bufpos)
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
||||
result.tokType = tkFloat64Lit
|
||||
eatChar(L, result, '.')
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
if L.buf[L.bufpos] in {'e', 'E'}:
|
||||
result.tokType = tkFloat64Lit
|
||||
eatChar(L, result, 'e')
|
||||
if L.buf[L.bufpos] in {'+', '-'}:
|
||||
eatChar(L, result)
|
||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||
endpos = L.bufpos
|
||||
if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
|
||||
if L.buf[endpos] == '\'': inc(endpos)
|
||||
L.bufpos = pos # restore position
|
||||
case L.buf[endpos]
|
||||
|
||||
# Second stage, find out if there's a datatype suffix and handle it
|
||||
var postPos = endpos
|
||||
if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
|
||||
if L.buf[postPos] == '\'':
|
||||
inc(postPos)
|
||||
|
||||
case L.buf[postPos]
|
||||
of 'f', 'F':
|
||||
inc(endpos)
|
||||
if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
|
||||
inc(postPos)
|
||||
if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
|
||||
result.tokType = tkFloat32Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
|
||||
result.tokType = tkFloat64Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '1') and
|
||||
(L.buf[endpos + 1] == '2') and
|
||||
(L.buf[endpos + 2] == '8'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '1') and
|
||||
(L.buf[postPos + 1] == '2') and
|
||||
(L.buf[postPos + 2] == '8'):
|
||||
result.tokType = tkFloat128Lit
|
||||
inc(endpos, 3)
|
||||
else:
|
||||
lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
|
||||
inc(postPos, 3)
|
||||
else: # "f" alone defaults to float32
|
||||
result.tokType = tkFloat32Lit
|
||||
of 'd', 'D': # ad hoc convenience shortcut for f64
|
||||
inc(postPos)
|
||||
result.tokType = tkFloat64Lit
|
||||
of 'i', 'I':
|
||||
inc(endpos)
|
||||
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
|
||||
inc(postPos)
|
||||
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
|
||||
result.tokType = tkInt64Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
|
||||
result.tokType = tkInt32Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
|
||||
result.tokType = tkInt16Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '8'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '8'):
|
||||
result.tokType = tkInt8Lit
|
||||
inc(endpos)
|
||||
inc(postPos)
|
||||
else:
|
||||
lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
|
||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
||||
of 'u', 'U':
|
||||
inc(endpos)
|
||||
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
|
||||
inc(postPos)
|
||||
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
|
||||
result.tokType = tkUInt64Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
|
||||
result.tokType = tkUInt32Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
|
||||
result.tokType = tkUInt16Lit
|
||||
inc(endpos, 2)
|
||||
elif (L.buf[endpos] == '8'):
|
||||
inc(postPos, 2)
|
||||
elif (L.buf[postPos] == '8'):
|
||||
result.tokType = tkUInt8Lit
|
||||
inc(endpos)
|
||||
inc(postPos)
|
||||
else:
|
||||
result.tokType = tkUIntLit
|
||||
else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
|
||||
else:
|
||||
L.bufpos = pos # restore position
|
||||
else:
|
||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
||||
|
||||
# Is there still a literalish char awaiting? Then it's an error!
|
||||
if L.buf[postPos] in literalishChars or
|
||||
(L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
|
||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
||||
|
||||
# Third stage, extract actual number
|
||||
L.bufpos = startpos # restore position
|
||||
var pos: int = startpos
|
||||
try:
|
||||
if (L.buf[pos] == '0') and
|
||||
(L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}):
|
||||
if (L.buf[pos] == '0') and (L.buf[pos + 1] in baseCodeChars):
|
||||
inc(pos, 2)
|
||||
xi = 0 # it may be a base prefix
|
||||
case L.buf[pos - 1] # now look at the optional type suffix:
|
||||
xi = 0 # it is a base prefix
|
||||
|
||||
case L.buf[pos - 1]
|
||||
of 'b', 'B':
|
||||
result.base = base2
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of '2'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
inc(pos)
|
||||
of '_':
|
||||
if L.buf[pos+1] notin {'0'..'1'}:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
inc(pos)
|
||||
of '0', '1':
|
||||
while pos < endpos:
|
||||
if L.buf[pos] != '_':
|
||||
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
else: break
|
||||
inc(pos)
|
||||
of 'o', 'c', 'C':
|
||||
result.base = base8
|
||||
while true:
|
||||
case L.buf[pos]
|
||||
of '8'..'9', '.':
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
inc(pos)
|
||||
of '_':
|
||||
if L.buf[pos+1] notin {'0'..'7'}:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
inc(pos)
|
||||
of '0'..'7':
|
||||
while pos < endpos:
|
||||
if L.buf[pos] != '_':
|
||||
xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
else: break
|
||||
of 'O':
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
inc(pos)
|
||||
of 'x', 'X':
|
||||
result.base = base16
|
||||
while true:
|
||||
while pos < endpos:
|
||||
case L.buf[pos]
|
||||
of '_':
|
||||
if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
inc(pos)
|
||||
of '0'..'9':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
|
||||
|
|
@ -408,51 +457,81 @@ proc getNumber(L: var TLexer): TToken =
|
|||
of 'A'..'F':
|
||||
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
|
||||
inc(pos)
|
||||
else: break
|
||||
else: internalError(getLineInfo(L), "getNumber")
|
||||
else:
|
||||
break
|
||||
else:
|
||||
internalError(getLineInfo(L), "getNumber")
|
||||
|
||||
case result.tokType
|
||||
of tkIntLit, tkInt64Lit: result.iNumber = xi
|
||||
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
|
||||
of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
|
||||
of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
|
||||
of tkInt16Lit: result.iNumber = BiggestInt(int16(toU16(int(xi))))
|
||||
of tkInt32Lit: result.iNumber = BiggestInt(int32(toU32(int64(xi))))
|
||||
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
|
||||
of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
|
||||
of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
|
||||
of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
|
||||
of tkUInt8Lit: result.iNumber = BiggestInt(uint8(toU8(int(xi))))
|
||||
of tkUInt16Lit: result.iNumber = BiggestInt(uint16(toU16(int(xi))))
|
||||
of tkUInt32Lit: result.iNumber = BiggestInt(uint32(toU32(int64(xi))))
|
||||
of tkFloat32Lit:
|
||||
result.fNumber = (cast[PFloat32](addr(xi)))[]
|
||||
# note: this code is endian neutral!
|
||||
# XXX: Test this on big endian machine!
|
||||
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
|
||||
else: internalError(getLineInfo(L), "getNumber")
|
||||
elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
|
||||
(result.tokType == tkFloat64Lit):
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
if result.tokType == tkIntLit: result.tokType = tkFloatLit
|
||||
elif result.tokType == tkUint64Lit:
|
||||
xi = 0
|
||||
let len = unsafeParseUInt(result.literal, xi)
|
||||
if len != result.literal.len or len == 0:
|
||||
raise newException(ValueError, "invalid integer: " & $xi)
|
||||
result.iNumber = xi
|
||||
|
||||
# Bounds checks. Non decimal literals are allowed to overflow the range of
|
||||
# the datatype as long as their pattern don't overflow _bitwise_, hence
|
||||
# below checks of signed sizes against uint*.high is deliberate:
|
||||
# (0x80'u8 = 128, 0x80'i8 = -128, etc == OK)
|
||||
if result.tokType notin floatTypes:
|
||||
let outOfRange = case result.tokType:
|
||||
of tkUInt8Lit, tkUInt16Lit, tkUInt32Lit: result.iNumber != xi
|
||||
of tkInt8Lit: (xi > BiggestInt(uint8.high))
|
||||
of tkInt16Lit: (xi > BiggestInt(uint16.high))
|
||||
of tkInt32Lit: (xi > BiggestInt(uint32.high))
|
||||
else: false
|
||||
|
||||
if outOfRange:
|
||||
#echo "out of range num: ", result.iNumber, " vs ", xi
|
||||
lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
||||
|
||||
else:
|
||||
result.iNumber = parseBiggestInt(result.literal)
|
||||
case result.tokType
|
||||
of floatTypes:
|
||||
result.fNumber = parseFloat(result.literal)
|
||||
of tkUint64Lit:
|
||||
xi = 0
|
||||
let len = unsafeParseUInt(result.literal, xi)
|
||||
if len != result.literal.len or len == 0:
|
||||
raise newException(ValueError, "invalid integer: " & $xi)
|
||||
result.iNumber = xi
|
||||
else:
|
||||
result.iNumber = parseBiggestInt(result.literal)
|
||||
|
||||
# Explicit bounds checks
|
||||
let outOfRange = case result.tokType:
|
||||
of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high)
|
||||
of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or
|
||||
result.iNumber > BiggestInt(uint8.high))
|
||||
of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high)
|
||||
of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or
|
||||
result.iNumber > BiggestInt(uint16.high))
|
||||
of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high)
|
||||
of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or
|
||||
result.iNumber > BiggestInt(uint32.high))
|
||||
else: false
|
||||
|
||||
if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
||||
|
||||
# Promote int literal to int64? Not always necessary, but more consistent
|
||||
if result.tokType == tkIntLit:
|
||||
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
|
||||
if result.tokType == tkIntLit:
|
||||
result.tokType = tkInt64Lit
|
||||
elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}:
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
elif result.tokType == tkInt8Lit and
|
||||
(result.iNumber < int8.low or result.iNumber > int8.high):
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
elif result.tokType == tkInt16Lit and
|
||||
(result.iNumber < int16.low or result.iNumber > int16.high):
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
result.tokType = tkInt64Lit
|
||||
|
||||
except ValueError:
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
||||
except OverflowError, RangeError:
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
L.bufpos = endpos
|
||||
lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
||||
L.bufpos = postPos
|
||||
|
||||
proc handleHexChar(L: var TLexer, xi: var int) =
|
||||
case L.buf[L.bufpos]
|
||||
|
|
@ -625,23 +704,34 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
|
|||
inc(L.bufpos) # skip '
|
||||
|
||||
proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||
var h: THash = 0
|
||||
var h: Hash = 0
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
case c
|
||||
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
|
||||
h = h !& ord(c)
|
||||
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:
|
||||
lexMessage(L, errInvalidToken, "–")
|
||||
break
|
||||
inc(pos, magicIdentSeparatorRuneByteWidth)
|
||||
else:
|
||||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
of 'A'..'Z':
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
inc(pos)
|
||||
of '_':
|
||||
if buf[pos+1] notin SymChars:
|
||||
lexMessage(L, errInvalidToken, "_")
|
||||
break
|
||||
inc(pos)
|
||||
|
||||
else: break
|
||||
inc(pos)
|
||||
h = !$h
|
||||
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
L.bufpos = pos
|
||||
|
|
@ -652,7 +742,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
|||
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
|
||||
|
||||
proc endOperator(L: var TLexer, tok: var TToken, pos: int,
|
||||
hash: THash) {.inline.} =
|
||||
hash: Hash) {.inline.} =
|
||||
var h = !$hash
|
||||
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
|
||||
if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
|
||||
|
|
@ -662,7 +752,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int,
|
|||
proc getOperator(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
var h: THash = 0
|
||||
var h: Hash = 0
|
||||
while true:
|
||||
var c = buf[pos]
|
||||
if c notin OpChars: break
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
# This module implements a generic doubled linked list.
|
||||
# TODO Remove this and replace it with something sensible
|
||||
import os
|
||||
type
|
||||
type
|
||||
PListEntry* = ref TListEntry
|
||||
TListEntry* = object of RootObj
|
||||
prev*, next*: PListEntry
|
||||
|
|
@ -25,68 +25,68 @@ type
|
|||
|
||||
TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}
|
||||
|
||||
proc initLinkedList*(list: var TLinkedList) =
|
||||
proc initLinkedList*(list: var TLinkedList) =
|
||||
list.counter = 0
|
||||
list.head = nil
|
||||
list.tail = nil
|
||||
|
||||
proc append*(list: var TLinkedList, entry: PListEntry) =
|
||||
proc append*(list: var TLinkedList, entry: PListEntry) =
|
||||
inc(list.counter)
|
||||
entry.next = nil
|
||||
entry.prev = list.tail
|
||||
if list.tail != nil:
|
||||
if list.tail != nil:
|
||||
assert(list.tail.next == nil)
|
||||
list.tail.next = entry
|
||||
list.tail = entry
|
||||
if list.head == nil: list.head = entry
|
||||
|
||||
proc contains*(list: TLinkedList, data: string): bool =
|
||||
|
||||
proc contains*(list: TLinkedList, data: string): bool =
|
||||
var it = list.head
|
||||
while it != nil:
|
||||
if PStrEntry(it).data == data:
|
||||
while it != nil:
|
||||
if PStrEntry(it).data == data:
|
||||
return true
|
||||
it = it.next
|
||||
|
||||
proc newStrEntry(data: string): PStrEntry =
|
||||
|
||||
proc newStrEntry(data: string): PStrEntry =
|
||||
new(result)
|
||||
result.data = data
|
||||
|
||||
proc appendStr*(list: var TLinkedList, data: string) =
|
||||
proc appendStr*(list: var TLinkedList, data: string) =
|
||||
append(list, newStrEntry(data))
|
||||
|
||||
proc includeStr*(list: var TLinkedList, data: string): bool =
|
||||
proc includeStr*(list: var TLinkedList, data: string): bool =
|
||||
if contains(list, data): return true
|
||||
appendStr(list, data) # else: add to list
|
||||
|
||||
proc prepend*(list: var TLinkedList, entry: PListEntry) =
|
||||
proc prepend*(list: var TLinkedList, entry: PListEntry) =
|
||||
inc(list.counter)
|
||||
entry.prev = nil
|
||||
entry.next = list.head
|
||||
if list.head != nil:
|
||||
if list.head != nil:
|
||||
assert(list.head.prev == nil)
|
||||
list.head.prev = entry
|
||||
list.head = entry
|
||||
if list.tail == nil: list.tail = entry
|
||||
|
||||
proc prependStr*(list: var TLinkedList, data: string) =
|
||||
proc prependStr*(list: var TLinkedList, data: string) =
|
||||
prepend(list, newStrEntry(data))
|
||||
|
||||
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
|
||||
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
|
||||
assert(pos != nil)
|
||||
if pos == list.head:
|
||||
if pos == list.head:
|
||||
prepend(list, entry)
|
||||
else:
|
||||
else:
|
||||
inc(list.counter)
|
||||
entry.next = pos
|
||||
entry.prev = pos.prev
|
||||
if pos.prev != nil: pos.prev.next = entry
|
||||
pos.prev = entry
|
||||
|
||||
proc remove*(list: var TLinkedList, entry: PListEntry) =
|
||||
|
||||
proc remove*(list: var TLinkedList, entry: PListEntry) =
|
||||
dec(list.counter)
|
||||
if entry == list.tail:
|
||||
if entry == list.tail:
|
||||
list.tail = entry.prev
|
||||
if entry == list.head:
|
||||
if entry == list.head:
|
||||
list.head = entry.next
|
||||
if entry.next != nil: entry.next.prev = entry.prev
|
||||
if entry.prev != nil: entry.prev.next = entry.next
|
||||
|
|
@ -112,8 +112,8 @@ proc excludePath*(list: var TLinkedList, data: string) =
|
|||
remove(list, it)
|
||||
it = nxt
|
||||
|
||||
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
||||
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
|
||||
result = list.head
|
||||
while result != nil:
|
||||
if fn(result, closure): return
|
||||
if fn(result, closure): return
|
||||
result = result.next
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@
|
|||
|
||||
## Low-level streams for high performance.
|
||||
|
||||
import
|
||||
import
|
||||
strutils
|
||||
|
||||
when not defined(windows) and defined(useGnuReadline):
|
||||
# support '-d:useGnuReadline' for backwards compatibility:
|
||||
when not defined(windows) and (defined(useGnuReadline) or defined(useLinenoise)):
|
||||
import rdstdin
|
||||
|
||||
type
|
||||
type
|
||||
TLLStreamKind* = enum # enum of different stream implementations
|
||||
llsNone, # null stream: reading and writing has no effect
|
||||
llsString, # stream encapsulates a string
|
||||
|
|
@ -27,42 +28,42 @@ type
|
|||
s*: string
|
||||
rd*, wr*: int # for string streams
|
||||
lineOffset*: int # for fake stdin line numbers
|
||||
|
||||
|
||||
PLLStream* = ref TLLStream
|
||||
|
||||
proc llStreamOpen*(data: string): PLLStream =
|
||||
proc llStreamOpen*(data: string): PLLStream =
|
||||
new(result)
|
||||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
if not open(result.f, filename, mode): result = nil
|
||||
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsNone
|
||||
|
||||
proc llStreamOpenStdIn*(): PLLStream =
|
||||
proc llStreamOpenStdIn*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsStdIn
|
||||
result.s = ""
|
||||
result.lineOffset = -1
|
||||
|
||||
proc llStreamClose*(s: PLLStream) =
|
||||
proc llStreamClose*(s: PLLStream) =
|
||||
case s.kind
|
||||
of llsNone, llsString, llsStdIn:
|
||||
of llsNone, llsString, llsStdIn:
|
||||
discard
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
close(s.f)
|
||||
|
||||
when not declared(readLineFromStdin):
|
||||
when not declared(readLineFromStdin):
|
||||
# fallback implementation:
|
||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||
stdout.write(prompt)
|
||||
|
|
@ -77,7 +78,7 @@ proc endsWith*(x: string, s: set[char]): bool =
|
|||
if i >= 0 and x[i] in s:
|
||||
result = true
|
||||
|
||||
const
|
||||
const
|
||||
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
|
||||
'|', '%', '&', '$', '@', '~', ','}
|
||||
AdditionalLineContinuationOprs = {'#', ':', '='}
|
||||
|
|
@ -104,31 +105,31 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
|||
s.rd = 0
|
||||
var line = newStringOfCap(120)
|
||||
var triples = 0
|
||||
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
|
||||
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
|
||||
add(s.s, line)
|
||||
add(s.s, "\n")
|
||||
inc triples, countTriples(line)
|
||||
if not continueLine(line, (triples and 1) == 1): break
|
||||
inc(s.lineOffset)
|
||||
result = min(bufLen, len(s.s) - s.rd)
|
||||
if result > 0:
|
||||
if result > 0:
|
||||
copyMem(buf, addr(s.s[s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
case s.kind
|
||||
of llsNone:
|
||||
of llsNone:
|
||||
result = 0
|
||||
of llsString:
|
||||
of llsString:
|
||||
result = min(bufLen, len(s.s) - s.rd)
|
||||
if result > 0:
|
||||
if result > 0:
|
||||
copyMem(buf, addr(s.s[0 + s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
result = readBuffer(s.f, buf, bufLen)
|
||||
of llsStdIn:
|
||||
of llsStdIn:
|
||||
result = llReadFromStdin(s, buf, bufLen)
|
||||
|
||||
|
||||
proc llStreamReadLine*(s: PLLStream, line: var string): bool =
|
||||
setLen(line, 0)
|
||||
case s.kind
|
||||
|
|
@ -152,60 +153,60 @@ proc llStreamReadLine*(s: PLLStream, line: var string): bool =
|
|||
result = readLine(s.f, line)
|
||||
of llsStdIn:
|
||||
result = readLine(stdin, line)
|
||||
|
||||
proc llStreamWrite*(s: PLLStream, data: string) =
|
||||
|
||||
proc llStreamWrite*(s: PLLStream, data: string) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
of llsNone, llsStdIn:
|
||||
discard
|
||||
of llsString:
|
||||
of llsString:
|
||||
add(s.s, data)
|
||||
inc(s.wr, len(data))
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
write(s.f, data)
|
||||
|
||||
proc llStreamWriteln*(s: PLLStream, data: string) =
|
||||
|
||||
proc llStreamWriteln*(s: PLLStream, data: string) =
|
||||
llStreamWrite(s, data)
|
||||
llStreamWrite(s, "\n")
|
||||
|
||||
proc llStreamWrite*(s: PLLStream, data: char) =
|
||||
proc llStreamWrite*(s: PLLStream, data: char) =
|
||||
var c: char
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
of llsNone, llsStdIn:
|
||||
discard
|
||||
of llsString:
|
||||
of llsString:
|
||||
add(s.s, data)
|
||||
inc(s.wr)
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
c = data
|
||||
discard writeBuffer(s.f, addr(c), sizeof(c))
|
||||
|
||||
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
|
||||
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
of llsNone, llsStdIn:
|
||||
discard
|
||||
of llsString:
|
||||
if buflen > 0:
|
||||
of llsString:
|
||||
if buflen > 0:
|
||||
setLen(s.s, len(s.s) + buflen)
|
||||
copyMem(addr(s.s[0 + s.wr]), buf, buflen)
|
||||
inc(s.wr, buflen)
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
discard writeBuffer(s.f, buf, buflen)
|
||||
|
||||
proc llStreamReadAll*(s: PLLStream): string =
|
||||
const
|
||||
|
||||
proc llStreamReadAll*(s: PLLStream): string =
|
||||
const
|
||||
bufSize = 2048
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
of llsNone, llsStdIn:
|
||||
result = ""
|
||||
of llsString:
|
||||
of llsString:
|
||||
if s.rd == 0: result = s.s
|
||||
else: result = substr(s.s, s.rd)
|
||||
s.rd = len(s.s)
|
||||
of llsFile:
|
||||
of llsFile:
|
||||
result = newString(bufSize)
|
||||
var bytes = readBuffer(s.f, addr(result[0]), bufSize)
|
||||
var i = bytes
|
||||
while bytes == bufSize:
|
||||
while bytes == bufSize:
|
||||
setLen(result, i + bufSize)
|
||||
bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
|
||||
inc(i, bytes)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
|
|||
result.typ = errorType(c)
|
||||
incl(result.flags, sfDiscardable)
|
||||
# pretend it's imported from some unknown module to prevent cascading errors:
|
||||
if gCmd != cmdInteractive and c.inCompilesContext == 0:
|
||||
if gCmd != cmdInteractive and c.compilesContextId == 0:
|
||||
c.importTable.addSym(result)
|
||||
|
||||
type
|
||||
|
|
|
|||
|
|
@ -63,6 +63,52 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
|||
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
|
||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
|
||||
|
||||
proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
|
||||
result = newNodeI(nkBracketExpr, tup.info)
|
||||
addSon(result, copyTree(tup))
|
||||
var lit = newNodeI(nkIntLit, tup.info)
|
||||
lit.intVal = i
|
||||
addSon(result, lit)
|
||||
|
||||
proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
|
||||
let value = n.lastSon
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
|
||||
var v = newNodeI(nkLetSection, value.info)
|
||||
let tempAsNode = newIdentNode(getIdent(genPrefix & $temp.id), value.info)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart.sons[0] = tempAsNode
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = value
|
||||
addSon(v, vpart)
|
||||
result.add(v)
|
||||
|
||||
let lhs = n.sons[0]
|
||||
for i in 0 .. lhs.len-1:
|
||||
result.add newAsgnStmt(lhs.sons[i], newTupleAccessRaw(tempAsNode, i))
|
||||
|
||||
proc lowerSwap*(n: PNode; owner: PSym): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
|
||||
var temp = newSym(skVar, getIdent(genPrefix), owner, n.info)
|
||||
temp.typ = n.sons[1].typ
|
||||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, v.info, 3)
|
||||
vpart.sons[0] = tempAsNode
|
||||
vpart.sons[1] = ast.emptyNode
|
||||
vpart.sons[2] = n[1]
|
||||
addSon(v, vpart)
|
||||
|
||||
result.add(v)
|
||||
result.add newFastAsgnStmt(n[1], n[2])
|
||||
result.add newFastAsgnStmt(n[2], tempAsNode)
|
||||
|
||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||
result = newType(tyObject, owner)
|
||||
rawAddSon(result, nil)
|
||||
|
|
@ -167,7 +213,7 @@ proc genDeref*(n: PNode): PNode =
|
|||
result.add n
|
||||
|
||||
proc callCodegenProc*(name: string, arg1: PNode;
|
||||
arg2, arg3: PNode = nil): PNode =
|
||||
arg2, arg3, optionalArgs: PNode = nil): PNode =
|
||||
result = newNodeI(nkCall, arg1.info)
|
||||
let sym = magicsys.getCompilerProc(name)
|
||||
if sym == nil:
|
||||
|
|
@ -177,6 +223,9 @@ proc callCodegenProc*(name: string, arg1: PNode;
|
|||
result.add arg1
|
||||
if arg2 != nil: result.add arg2
|
||||
if arg3 != nil: result.add arg3
|
||||
if optionalArgs != nil:
|
||||
for i in 1..optionalArgs.len-3:
|
||||
result.add optionalArgs[i]
|
||||
result.typ = sym.typ.sons[0]
|
||||
|
||||
proc callProc(a: PNode): PNode =
|
||||
|
|
@ -483,7 +532,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
|||
barrier, dest: PNode = nil): PNode =
|
||||
# if 'barrier' != nil, then it is in a 'parallel' section and we
|
||||
# generate quite different code
|
||||
let n = spawnExpr[1]
|
||||
let n = spawnExpr[^2]
|
||||
let spawnKind = spawnResult(retType, barrier!=nil)
|
||||
case spawnKind
|
||||
of srVoid:
|
||||
|
|
@ -569,7 +618,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
|||
fvField = newDotExpr(scratchObj, field)
|
||||
fvAsExpr = indirectAccess(castExpr, field, n.info)
|
||||
# create flowVar:
|
||||
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
|
||||
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
|
||||
if barrier == nil:
|
||||
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
|
||||
|
||||
|
|
@ -584,7 +633,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
|||
let wrapper = createWrapperProc(fn, threadParam, argsParam,
|
||||
varSection, varInit, call,
|
||||
barrierAsExpr, fvAsExpr, spawnKind)
|
||||
result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
|
||||
genAddrOf(scratchObj.newSymNode))
|
||||
result.add callCodegenProc("nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
|
||||
genAddrOf(scratchObj.newSymNode), nil, spawnExpr)
|
||||
|
||||
if spawnKind == srFlowVar: result.add fvField
|
||||
|
|
|
|||
|
|
@ -9,43 +9,35 @@
|
|||
|
||||
# Built-in types and compilerprocs are registered here.
|
||||
|
||||
import
|
||||
import
|
||||
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
|
||||
|
||||
var systemModule*: PSym
|
||||
|
||||
proc registerSysType*(t: PType)
|
||||
# magic symbols in the system module:
|
||||
proc getSysType*(kind: TTypeKind): PType
|
||||
proc getCompilerProc*(name: string): PSym
|
||||
proc registerCompilerProc*(s: PSym)
|
||||
proc finishSystem*(tab: TStrTable)
|
||||
proc getSysSym*(name: string): PSym
|
||||
# implementation
|
||||
|
||||
var
|
||||
gSysTypes: array[TTypeKind, PType]
|
||||
compilerprocs: TStrTable
|
||||
exposed: TStrTable
|
||||
|
||||
proc nilOrSysInt*: PType = gSysTypes[tyInt]
|
||||
|
||||
proc registerSysType(t: PType) =
|
||||
proc registerSysType*(t: PType) =
|
||||
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
|
||||
|
||||
proc newSysType(kind: TTypeKind, size: int): PType =
|
||||
|
||||
proc newSysType(kind: TTypeKind, size: int): PType =
|
||||
result = newType(kind, systemModule)
|
||||
result.size = size
|
||||
result.align = size.int16
|
||||
|
||||
proc getSysSym(name: string): PSym =
|
||||
proc getSysSym*(name: string): PSym =
|
||||
result = strTableGet(systemModule.tab, getIdent(name))
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
|
||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||
var ti: TIdentIter
|
||||
let id = getIdent(name)
|
||||
|
|
@ -57,13 +49,13 @@ proc getSysMagic*(name: string, m: TMagic): PSym =
|
|||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, id, systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
|
||||
proc sysTypeFromName*(name: string): PType =
|
||||
|
||||
proc sysTypeFromName*(name: string): PType =
|
||||
result = getSysSym(name).typ
|
||||
|
||||
proc getSysType(kind: TTypeKind): PType =
|
||||
proc getSysType*(kind: TTypeKind): PType =
|
||||
result = gSysTypes[kind]
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
case kind
|
||||
of tyInt: result = sysTypeFromName("int")
|
||||
of tyInt8: result = sysTypeFromName("int8")
|
||||
|
|
@ -87,7 +79,7 @@ proc getSysType(kind: TTypeKind): PType =
|
|||
of tyNil: result = newSysType(tyNil, ptrSize)
|
||||
else: internalError("request for typekind: " & $kind)
|
||||
gSysTypes[kind] = result
|
||||
if result.kind != kind:
|
||||
if result.kind != kind:
|
||||
internalError("wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: internalError("type not found: " & $kind)
|
||||
|
||||
|
|
@ -97,6 +89,7 @@ var
|
|||
proc resetSysTypes* =
|
||||
systemModule = nil
|
||||
initStrTable(compilerprocs)
|
||||
initStrTable(exposed)
|
||||
for i in low(gSysTypes)..high(gSysTypes):
|
||||
gSysTypes[i] = nil
|
||||
|
||||
|
|
@ -163,8 +156,8 @@ proc setIntLitType*(result: PNode) =
|
|||
result.typ = getSysType(tyInt64)
|
||||
else: internalError(result.info, "invalid int size")
|
||||
|
||||
proc getCompilerProc(name: string): PSym =
|
||||
var ident = getIdent(name, hashIgnoreStyle(name))
|
||||
proc getCompilerProc*(name: string): PSym =
|
||||
let ident = getIdent(name)
|
||||
result = strTableGet(compilerprocs, ident)
|
||||
if result == nil:
|
||||
result = strTableGet(rodCompilerprocs, ident)
|
||||
|
|
@ -173,9 +166,22 @@ proc getCompilerProc(name: string): PSym =
|
|||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc registerCompilerProc(s: PSym) =
|
||||
proc registerCompilerProc*(s: PSym) =
|
||||
strTableAdd(compilerprocs, s)
|
||||
|
||||
proc finishSystem(tab: TStrTable) = discard
|
||||
proc registerNimScriptSymbol*(s: PSym) =
|
||||
# Nimscript symbols must be al unique:
|
||||
let conflict = strTableGet(exposed, s.name)
|
||||
if conflict == nil:
|
||||
strTableAdd(exposed, s)
|
||||
else:
|
||||
localError(s.info, "symbol conflicts with other .exportNims symbol at: " &
|
||||
$conflict.info)
|
||||
|
||||
proc getNimScriptSymbol*(name: string): PSym =
|
||||
strTableGet(exposed, getIdent(name))
|
||||
|
||||
proc resetNimScriptSymbols*() = initStrTable(exposed)
|
||||
|
||||
initStrTable(compilerprocs)
|
||||
initStrTable(exposed)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import
|
|||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||
cgen, jsgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||
docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||
|
||||
from magicsys import systemModule, resetSysTypes
|
||||
|
||||
|
|
@ -63,14 +63,14 @@ proc commandCompileToC =
|
|||
compileProject()
|
||||
cgenWriteModules()
|
||||
if gCmd != cmdRun:
|
||||
extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
|
||||
extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
|
||||
|
||||
if isServing:
|
||||
# caas will keep track only of the compilation commands
|
||||
lastCaasCmd = curCaasCmd
|
||||
resetCgenModules()
|
||||
for i in 0 .. <gMemCacheData.len:
|
||||
gMemCacheData[i].crcStatus = crcCached
|
||||
gMemCacheData[i].hashStatus = hashCached
|
||||
gMemCacheData[i].needsRecompile = Maybe
|
||||
|
||||
# XXX: clean these global vars
|
||||
|
|
@ -116,7 +116,7 @@ proc interactivePasses =
|
|||
#incl(gGlobalOptions, optSafeCode)
|
||||
#setTarget(osNimrodVM, cpuNimrodVM)
|
||||
initDefines()
|
||||
defineSymbol("nimrodvm")
|
||||
defineSymbol("nimscript")
|
||||
when hasFFI: defineSymbol("nimffi")
|
||||
registerPass(verbosePass)
|
||||
registerPass(semPass)
|
||||
|
|
@ -190,7 +190,6 @@ proc resetMemory =
|
|||
resetRopeCache()
|
||||
resetSysTypes()
|
||||
gOwners = @[]
|
||||
rangeDestructorProc = nil
|
||||
for i in low(buckets)..high(buckets):
|
||||
buckets[i] = nil
|
||||
idAnon = nil
|
||||
|
|
@ -237,7 +236,7 @@ proc mainCommand* =
|
|||
when SimulateCaasMemReset:
|
||||
gGlobalOptions.incl(optCaasEnabled)
|
||||
|
||||
# In "nimrod serve" scenario, each command must reset the registered passes
|
||||
# In "nim serve" scenario, each command must reset the registered passes
|
||||
clearPasses()
|
||||
gLastCmdTime = epochTime()
|
||||
appendStr(searchPaths, options.libpath)
|
||||
|
|
@ -318,11 +317,12 @@ proc mainCommand* =
|
|||
(key: "lib_paths", val: libpaths)
|
||||
]
|
||||
|
||||
outWriteln($dumpdata)
|
||||
msgWriteln($dumpdata, {msgStdout, msgSkipHook})
|
||||
else:
|
||||
outWriteln("-- list of currently defined symbols --")
|
||||
for s in definedSymbolNames(): outWriteln(s)
|
||||
outWriteln("-- end of list --")
|
||||
msgWriteln("-- list of currently defined symbols --",
|
||||
{msgStdout, msgSkipHook})
|
||||
for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook})
|
||||
msgWriteln("-- end of list --", {msgStdout, msgSkipHook})
|
||||
|
||||
for it in iterSearchPath(searchPaths): msgWriteln(it)
|
||||
of "check":
|
||||
|
|
@ -337,7 +337,7 @@ proc mainCommand* =
|
|||
wantMainModule()
|
||||
commandScan()
|
||||
msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||
of "i":
|
||||
of "secret":
|
||||
gCmd = cmdInteractive
|
||||
commandInteractive()
|
||||
of "e":
|
||||
|
|
@ -356,12 +356,14 @@ proc mainCommand* =
|
|||
gGlobalOptions.incl(optCaasEnabled)
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
serve(mainCommand)
|
||||
of "nop", "help":
|
||||
# prevent the "success" message:
|
||||
gCmd = cmdDump
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
|
||||
if (msgs.gErrorCounter == 0 and
|
||||
gCmd notin {cmdInterpret, cmdRun, cmdDump} and
|
||||
gVerbosity > 0):
|
||||
if msgs.gErrorCounter == 0 and
|
||||
gCmd notin {cmdInterpret, cmdRun, cmdDump}:
|
||||
rawMessage(hintSuccessX, [$gLinesCompiled,
|
||||
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
|
||||
formatSize(getTotalMem()),
|
||||
|
|
@ -379,3 +381,4 @@ proc mainCommand* =
|
|||
when SimulateCaasMemReset:
|
||||
resetMemory()
|
||||
|
||||
resetAttributes()
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@
|
|||
## implements the module handling
|
||||
|
||||
import
|
||||
ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes
|
||||
ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes, llstream
|
||||
|
||||
type
|
||||
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
|
||||
TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
|
||||
THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
|
||||
|
||||
TModuleInMemory* = object
|
||||
compiledAt*: float
|
||||
crc*: TCrc32
|
||||
hash*: SecureHash
|
||||
deps*: seq[int32] ## XXX: slurped files are currently not tracked
|
||||
needsRecompile*: TNeedRecompile
|
||||
crcStatus*: TCrcStatus
|
||||
hashStatus*: THashStatus
|
||||
|
||||
var
|
||||
gCompiledModules: seq[PSym] = @[]
|
||||
|
|
@ -34,36 +34,36 @@ proc getModule(fileIdx: int32): PSym =
|
|||
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||
result = gCompiledModules[fileIdx]
|
||||
|
||||
template crc(x: PSym): expr =
|
||||
gMemCacheData[x.position].crc
|
||||
template hash(x: PSym): expr =
|
||||
gMemCacheData[x.position].hash
|
||||
|
||||
proc crcChanged(fileIdx: int32): bool =
|
||||
proc hashChanged(fileIdx: int32): bool =
|
||||
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
||||
|
||||
|
||||
template updateStatus =
|
||||
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
|
||||
else: crcNotChanged
|
||||
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result
|
||||
|
||||
case gMemCacheData[fileIdx].crcStatus:
|
||||
of crcHasChanged:
|
||||
gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged
|
||||
else: hashNotChanged
|
||||
# echo "TESTING Hash: ", fileIdx.toFilename, " ", result
|
||||
|
||||
case gMemCacheData[fileIdx].hashStatus:
|
||||
of hashHasChanged:
|
||||
result = true
|
||||
of crcNotChanged:
|
||||
of hashNotChanged:
|
||||
result = false
|
||||
of crcCached:
|
||||
let newCrc = crcFromFile(fileIdx.toFilename)
|
||||
result = newCrc != gMemCacheData[fileIdx].crc
|
||||
gMemCacheData[fileIdx].crc = newCrc
|
||||
of hashCached:
|
||||
let newHash = secureHashFile(fileIdx.toFullPath)
|
||||
result = newHash != gMemCacheData[fileIdx].hash
|
||||
gMemCacheData[fileIdx].hash = newHash
|
||||
updateStatus()
|
||||
of crcNotTaken:
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
of hashNotTaken:
|
||||
gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
|
||||
result = true
|
||||
updateStatus()
|
||||
|
||||
proc doCRC(fileIdx: int32) =
|
||||
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
|
||||
# echo "FIRST CRC: ", fileIdx.ToFilename
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
proc doHash(fileIdx: int32) =
|
||||
if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
|
||||
# echo "FIRST Hash: ", fileIdx.ToFilename
|
||||
gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
|
||||
|
||||
proc addDep(x: PSym, dep: int32) =
|
||||
growCache gMemCacheData, dep
|
||||
|
|
@ -78,6 +78,13 @@ proc resetModule*(fileIdx: int32) =
|
|||
if fileIdx <% cgendata.gModules.len:
|
||||
cgendata.gModules[fileIdx] = nil
|
||||
|
||||
proc resetModule*(module: PSym) =
|
||||
let conflict = getModule(module.position.int32)
|
||||
if conflict == nil: return
|
||||
doAssert conflict == module
|
||||
resetModule(module.position.int32)
|
||||
initStrTable(module.tab)
|
||||
|
||||
proc resetAllModules* =
|
||||
for i in 0..gCompiledModules.high:
|
||||
if gCompiledModules[i] != nil:
|
||||
|
|
@ -85,6 +92,14 @@ proc resetAllModules* =
|
|||
resetPackageCache()
|
||||
# for m in cgenModules(): echo "CGEN MODULE FOUND"
|
||||
|
||||
proc resetAllModulesHard* =
|
||||
resetPackageCache()
|
||||
gCompiledModules.setLen 0
|
||||
gMemCacheData.setLen 0
|
||||
magicsys.resetSysTypes()
|
||||
# XXX
|
||||
#gOwners = @[]
|
||||
|
||||
proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
||||
template markDirty =
|
||||
resetModule(fileIdx)
|
||||
|
|
@ -94,9 +109,9 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
|||
return gMemCacheData[fileIdx].needsRecompile
|
||||
|
||||
if optForceFullMake in gGlobalOptions or
|
||||
crcChanged(fileIdx):
|
||||
hashChanged(fileIdx):
|
||||
markDirty
|
||||
|
||||
|
||||
if gMemCacheData[fileIdx].deps != nil:
|
||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
||||
for dep in gMemCacheData[fileIdx].deps:
|
||||
|
|
@ -104,30 +119,30 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
|||
if d in {Yes, Recompiled}:
|
||||
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
|
||||
markDirty
|
||||
|
||||
|
||||
gMemCacheData[fileIdx].needsRecompile = No
|
||||
return No
|
||||
|
||||
proc newModule(fileIdx: int32): PSym =
|
||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
# mechanism, which we do in order to assign each module a persistent ID.
|
||||
new(result)
|
||||
result.id = - 1 # for better error checking
|
||||
result.kind = skModule
|
||||
let filename = fileIdx.toFullPath
|
||||
result.name = getIdent(splitFile(filename).name)
|
||||
if result.name.s != "-" and not isNimIdentifier(result.name.s):
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
|
||||
result.info)
|
||||
result.position = fileIdx
|
||||
|
||||
|
||||
growCache gMemCacheData, fileIdx
|
||||
growCache gCompiledModules, fileIdx
|
||||
gCompiledModules[result.position] = result
|
||||
|
||||
|
||||
incl(result.flags, sfUsed)
|
||||
initStrTable(result.tab)
|
||||
strTableAdd(result.tab, result) # a module knows itself
|
||||
|
|
@ -143,16 +158,19 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
|
|||
result.flags = result.flags + flags
|
||||
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
|
||||
rd = handleSymbolFile(result)
|
||||
if result.id < 0:
|
||||
if result.id < 0:
|
||||
internalError("handleSymbolFile should have set the module\'s ID")
|
||||
return
|
||||
else:
|
||||
result.id = getID()
|
||||
processModule(result, nil, rd)
|
||||
if sfMainModule in flags and gProjectIsStdin:
|
||||
processModule(result, llStreamOpen(stdin), rd)
|
||||
else:
|
||||
processModule(result, nil, rd)
|
||||
if optCaasEnabled in gGlobalOptions:
|
||||
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
|
||||
gMemCacheData[fileIdx].needsRecompile = Recompiled
|
||||
doCRC fileIdx
|
||||
doHash fileIdx
|
||||
else:
|
||||
if checkDepMem(fileIdx) == Yes:
|
||||
result = compileModule(fileIdx, flags)
|
||||
|
|
@ -171,7 +189,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
|||
if optCaasEnabled in gGlobalOptions:
|
||||
growCache gMemCacheData, fileIdx
|
||||
addDep(s, fileIdx)
|
||||
doCRC(fileIdx)
|
||||
doHash(fileIdx)
|
||||
|
||||
proc `==^`(a, b: string): bool =
|
||||
try:
|
||||
|
|
@ -202,9 +220,8 @@ proc compileProject*(projectFileIdx = -1'i32) =
|
|||
compileSystemModule()
|
||||
discard compileModule(projectFile, {sfMainModule})
|
||||
|
||||
var stdinModule: PSym
|
||||
proc makeStdinModule*(): PSym =
|
||||
if stdinModule == nil:
|
||||
stdinModule = newModule(fileInfoIdx"stdin")
|
||||
stdinModule.id = getID()
|
||||
result = stdinModule
|
||||
proc makeModule*(filename: string): PSym =
|
||||
result = newModule(fileInfoIdx filename)
|
||||
result.id = getID()
|
||||
|
||||
proc makeStdinModule*(): PSym = makeModule"stdin"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#
|
||||
|
||||
import
|
||||
options, strutils, os, tables, ropes, platform
|
||||
options, strutils, os, tables, ropes, platform, terminal, macros
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
|
|
@ -17,10 +17,9 @@ type
|
|||
errIntLiteralExpected, errInvalidCharacterConstant,
|
||||
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
||||
errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
|
||||
errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
|
||||
errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
|
||||
errNewlineExpected,
|
||||
errInvalidModuleName,
|
||||
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
|
||||
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
|
||||
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
|
||||
errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
|
||||
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
|
||||
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
|
||||
|
|
@ -31,11 +30,14 @@ type
|
|||
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
|
||||
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
|
||||
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
|
||||
errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
|
||||
errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound,
|
||||
errNoneBoehmRefcExpectedButXFound,
|
||||
errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
|
||||
errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
|
||||
errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
|
||||
errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
|
||||
errExprExpected, errUndeclaredIdentifier, errUndeclaredField,
|
||||
errUndeclaredRoutine, errUseQualifier,
|
||||
errTypeExpected,
|
||||
errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
|
||||
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
|
||||
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
|
||||
|
|
@ -80,7 +82,7 @@ type
|
|||
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
|
||||
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
|
||||
errNoReturnTypeDeclared,
|
||||
errInvalidCommandX, errXOnlyAtModuleScope,
|
||||
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
|
||||
errXNeedsParamObjectType,
|
||||
errTemplateInstantiationTooNested, errInstantiationFrom,
|
||||
errInvalidIndexValueForTuple, errCommandExpectsFilename,
|
||||
|
|
@ -106,6 +108,8 @@ type
|
|||
errCannotInferReturnType,
|
||||
errGenericLambdaNotAllowed,
|
||||
errCompilerDoesntSupportTarget,
|
||||
errExternalAssemblerNotFound,
|
||||
errExternalAssemblerNotValid,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
|
|
@ -114,7 +118,7 @@ type
|
|||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnNilStatement, warnTypelessParam,
|
||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
|
|
@ -124,6 +128,8 @@ type
|
|||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintExecuting, hintLinking, hintDependency,
|
||||
hintSource, hintStackTrace, hintGCStats,
|
||||
hintUser
|
||||
|
||||
const
|
||||
|
|
@ -143,6 +149,7 @@ const
|
|||
errInvalidToken: "invalid token: $1",
|
||||
errLineTooLong: "line too long",
|
||||
errInvalidNumber: "$1 is not a valid number",
|
||||
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
|
||||
errNumberOutOfRange: "number $1 out of valid range",
|
||||
errNnotAllowedInCharacter: "\\n not allowed in character literal",
|
||||
errClosingBracketExpected: "closing ']' expected, but end of file reached",
|
||||
|
|
@ -179,6 +186,7 @@ const
|
|||
errUnknownVar: "unknown variable: \'$1\'",
|
||||
errUnknownCcompiler: "unknown C compiler: \'$1\'",
|
||||
errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
|
||||
errOnOffOrListExpectedButXFound: "\'on\', \'off\' or \'list\' expected, but \'$1\' found",
|
||||
errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
|
||||
errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
|
||||
errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
|
||||
|
|
@ -190,10 +198,12 @@ const
|
|||
errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
|
||||
errExprExpected: "expression expected, but found \'$1\'",
|
||||
errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
|
||||
errUndeclaredField: "undeclared field: \'$1\'",
|
||||
errUndeclaredRoutine: "attempting to call undeclared routine: \'$1\'",
|
||||
errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
|
||||
errTypeExpected: "type expected",
|
||||
errSystemNeeds: "system module needs \'$1\'",
|
||||
errExecutionOfProgramFailed: "execution of an external program failed",
|
||||
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
|
||||
errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
|
||||
errInvalidArgForX: "invalid argument for \'$1\'",
|
||||
errStmtHasNoEffect: "statement has no effect",
|
||||
|
|
@ -308,6 +318,7 @@ const
|
|||
errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
|
||||
errXNeedsReturnType: "$1 needs a return type",
|
||||
errNoReturnTypeDeclared: "no return type declared",
|
||||
errNoCommand: "no command given",
|
||||
errInvalidCommandX: "invalid command: \'$1\'",
|
||||
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
|
||||
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
|
||||
|
|
@ -362,55 +373,63 @@ const
|
|||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be inferred from the expected signature.",
|
||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||
errExternalAssemblerNotFound: "External assembler not found",
|
||||
errExternalAssemblerNotValid: "External assembler '$1' is not a valid assembler",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
|
||||
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
|
||||
warnDeprecated: "$1 is deprecated [Deprecated]",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
|
||||
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
|
||||
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
|
||||
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
|
||||
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
|
||||
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
|
||||
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
|
||||
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
|
||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
|
||||
warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
|
||||
warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
|
||||
warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]",
|
||||
warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]",
|
||||
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
||||
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
||||
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
||||
warnCannotOpenFile: "cannot open \'$1\'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
warnXIsNeverRead: "\'$1\' is never read",
|
||||
warnXmightNotBeenInit: "\'$1\' might not have been initialized",
|
||||
warnDeprecated: "$1 is deprecated",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated",
|
||||
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)",
|
||||
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler",
|
||||
warnRedefinitionOfLabel: "redefinition of label \'$1\'",
|
||||
warnUnknownSubstitutionX: "unknown substitution \'$1\'",
|
||||
warnLanguageXNotSupported: "language \'$1\' not supported",
|
||||
warnFieldXNotSupported: "field \'$1\' not supported",
|
||||
warnCommentXIgnored: "comment \'$1\' ignored",
|
||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||
warnWriteToForeignHeap: "write to foreign heap",
|
||||
warnUnsafeCode: "unsafe code: '$1'",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple",
|
||||
warnShadowIdent: "shadowed identifier: '$1'",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
|
||||
warnProveField: "cannot prove that field '$1' is accessible",
|
||||
warnProveIndex: "cannot prove index '$1' is valid",
|
||||
warnGcUnsafe: "not GC-safe: '$1'",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized [Uninit]",
|
||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
|
||||
warnLockLevel: "$1 [LockLevel]",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
|
||||
warnUser: "$1 [User]",
|
||||
hintSuccess: "operation successful [Success]",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]",
|
||||
hintLineTooLong: "line too long [LineTooLong]",
|
||||
hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]",
|
||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]",
|
||||
hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]",
|
||||
hintQuitCalled: "quit() called [QuitCalled]",
|
||||
hintProcessing: "$1 [Processing]",
|
||||
hintCodeBegin: "generated code listing: [CodeBegin]",
|
||||
hintCodeEnd: "end of listing [CodeEnd]",
|
||||
hintConf: "used config file \'$1\' [Conf]",
|
||||
hintPath: "added path: '$1' [Path]",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
|
||||
hintName: "name should be: '$1' [Name]",
|
||||
hintPattern: "$1 [Pattern]",
|
||||
hintUser: "$1 [User]"]
|
||||
warnUninit: "'$1' might not have been initialized",
|
||||
warnGcMem: "'$1' uses GC'ed memory",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
|
||||
warnLockLevel: "$1",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "\'$1\' is declared but not used",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
||||
hintExprAlwaysX: "expression evaluates always to \'$1\'",
|
||||
hintQuitCalled: "quit() called",
|
||||
hintProcessing: "$1",
|
||||
hintCodeBegin: "generated code listing:",
|
||||
hintCodeEnd: "end of listing",
|
||||
hintConf: "used config file \'$1\'",
|
||||
hintPath: "added path: '$1'",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1'",
|
||||
hintName: "name should be: '$1'",
|
||||
hintPattern: "$1",
|
||||
hintExecuting: "$1",
|
||||
hintLinking: "",
|
||||
hintDependency: "$1",
|
||||
hintSource: "$1",
|
||||
hintStackTrace: "$1",
|
||||
hintGCStats: "$1",
|
||||
hintUser: "$1"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||
|
|
@ -420,15 +439,16 @@ const
|
|||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored", "NilStmt",
|
||||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||
|
||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
HintsToStr*: array[0..22, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "StackTrace", "GCStats",
|
||||
"User"]
|
||||
|
||||
const
|
||||
|
|
@ -449,10 +469,10 @@ type
|
|||
fullPath: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
quotedName*: Rope # cached quoted short name for codegen
|
||||
# purposes
|
||||
|
||||
lines*: seq[Rope] # the source code of the module
|
||||
lines*: seq[Rope] # the source code of the module
|
||||
# used for better error messages and
|
||||
# embedding the original source in the
|
||||
# generated code
|
||||
|
|
@ -479,6 +499,30 @@ type
|
|||
ERecoverableError* = object of ValueError
|
||||
ESuggestDone* = object of Exception
|
||||
|
||||
const
|
||||
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintSuccessX, hintPath, hintConf,
|
||||
hintProcessing,
|
||||
hintDependency,
|
||||
hintExecuting, hintLinking,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintPath, hintConf,
|
||||
hintDependency,
|
||||
hintExecuting,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace},
|
||||
{low(TNoteKind)..high(TNoteKind)}]
|
||||
|
||||
const
|
||||
InvalidFileIDX* = int32(-1)
|
||||
|
||||
|
|
@ -567,9 +611,7 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
|||
proc sourceLine*(i: TLineInfo): Rope
|
||||
|
||||
var
|
||||
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
|
||||
{warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex, warnGcUnsafe}
|
||||
gNotes*: TNoteKinds = NotesVerbosity[1] # defaults to verbosity of 1
|
||||
gErrorCounter*: int = 0 # counts the number of errors
|
||||
gHintCounter*: int = 0
|
||||
gWarnCounter*: int = 0
|
||||
|
|
@ -589,8 +631,11 @@ var
|
|||
|
||||
proc suggestWriteln*(s: string) =
|
||||
if eStdOut in errorOutputs:
|
||||
if isNil(writelnHook): writeln(stdout, s)
|
||||
else: writelnHook(s)
|
||||
if isNil(writelnHook):
|
||||
writeLine(stdout, s)
|
||||
flushFile(stdout)
|
||||
else:
|
||||
writelnHook(s)
|
||||
|
||||
proc msgQuit*(x: int8) = quit x
|
||||
proc msgQuit*(x: string) = quit x
|
||||
|
|
@ -601,13 +646,17 @@ proc suggestQuit*() =
|
|||
# this format is understood by many text editors: it is the same that
|
||||
# Borland and Freepascal use
|
||||
const
|
||||
PosErrorFormat* = "$1($2, $3) Error: $4"
|
||||
PosWarningFormat* = "$1($2, $3) Warning: $4"
|
||||
PosHintFormat* = "$1($2, $3) Hint: $4"
|
||||
PosContextFormat = "$1($2, $3) Info: $4"
|
||||
RawErrorFormat* = "Error: $1"
|
||||
RawWarningFormat* = "Warning: $1"
|
||||
RawHintFormat* = "Hint: $1"
|
||||
PosFormat = "$1($2, $3) "
|
||||
KindFormat = " [$1]"
|
||||
KindColor = fgCyan
|
||||
ErrorTitle = "Error: "
|
||||
ErrorColor = fgRed
|
||||
WarningTitle = "Warning: "
|
||||
WarningColor = fgYellow
|
||||
HintTitle = "Hint: "
|
||||
HintColor = fgGreen
|
||||
InfoTitle = "Info: "
|
||||
InfoColor = fgCyan
|
||||
|
||||
proc getInfoContextLen*(): int = return msgContext.len
|
||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||
|
|
@ -678,21 +727,79 @@ proc `??`* (info: TLineInfo, filename: string): bool =
|
|||
|
||||
var gTrackPos*: TLineInfo
|
||||
|
||||
proc outWriteln*(s: string) =
|
||||
## Writes to stdout. Always.
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
type
|
||||
MsgFlag* = enum ## flags altering msgWriteln behavior
|
||||
msgStdout, ## force writing to stdout, even stderr is default
|
||||
msgSkipHook ## skip message hook even if it is present
|
||||
MsgFlags* = set[MsgFlag]
|
||||
|
||||
proc msgWriteln*(s: string) =
|
||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||
proc msgWriteln*(s: string, flags: MsgFlags = {}) =
|
||||
## Writes given message string to stderr by default.
|
||||
## If ``--stdout`` option is given, writes to stdout instead. If message hook
|
||||
## is present, then it is used to output message rather than stderr/stdout.
|
||||
## This behavior can be altered by given optional flags.
|
||||
|
||||
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
if not isNil(writelnHook):
|
||||
if not isNil(writelnHook) and msgSkipHook notin flags:
|
||||
writelnHook(s)
|
||||
elif optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs: writeln(stderr, s)
|
||||
elif optStdout in gGlobalOptions or msgStdout in flags:
|
||||
if eStdOut in errorOutputs:
|
||||
writeLine(stdout, s)
|
||||
flushFile(stdout)
|
||||
else:
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
if eStdErr in errorOutputs:
|
||||
writeLine(stderr, s)
|
||||
# On Windows stderr is fully-buffered when piped, regardless of C std.
|
||||
when defined(windows):
|
||||
flushFile(stderr)
|
||||
|
||||
macro callIgnoringStyle(theProc: typed, first: typed,
|
||||
args: varargs[expr]): stmt =
|
||||
let typForegroundColor = bindSym"ForegroundColor".getType
|
||||
let typBackgroundColor = bindSym"BackgroundColor".getType
|
||||
let typStyle = bindSym"Style".getType
|
||||
let typTerminalCmd = bindSym"TerminalCmd".getType
|
||||
result = newCall(theProc)
|
||||
if first.kind != nnkNilLit: result.add(first)
|
||||
for arg in children(args[0][1]):
|
||||
if arg.kind == nnkNilLit: continue
|
||||
let typ = arg.getType
|
||||
if typ.kind != nnkEnumTy or
|
||||
typ != typForegroundColor and
|
||||
typ != typBackgroundColor and
|
||||
typ != typStyle and
|
||||
typ != typTerminalCmd:
|
||||
result.add(arg)
|
||||
|
||||
macro callStyledWriteLineStderr(args: varargs[expr]): stmt =
|
||||
result = newCall(bindSym"styledWriteLine")
|
||||
result.add(bindSym"stderr")
|
||||
for arg in children(args[0][1]):
|
||||
result.add(arg)
|
||||
|
||||
template callWritelnHook(args: varargs[string, `$`]) =
|
||||
var s = ""
|
||||
for arg in args:
|
||||
s.add arg
|
||||
writelnHook s
|
||||
|
||||
template styledMsgWriteln*(args: varargs[expr]) =
|
||||
if not isNil(writelnHook):
|
||||
callIgnoringStyle(callWritelnHook, nil, args)
|
||||
elif optStdout in gGlobalOptions:
|
||||
if eStdOut in errorOutputs:
|
||||
callIgnoringStyle(writeLine, stdout, args)
|
||||
flushFile(stdout)
|
||||
else:
|
||||
if eStdErr in errorOutputs:
|
||||
if optUseColors in gGlobalOptions:
|
||||
callStyledWriteLineStderr(args)
|
||||
else:
|
||||
callIgnoringStyle(writeLine, stderr, args)
|
||||
# On Windows stderr is fully-buffered when piped, regardless of C std.
|
||||
when defined(windows):
|
||||
flushFile(stderr)
|
||||
|
||||
proc coordToStr(coord: int): string =
|
||||
if coord == -1: result = "???"
|
||||
|
|
@ -710,11 +817,11 @@ type
|
|||
|
||||
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
template quit =
|
||||
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
|
||||
if defined(debug) or msg == errInternal or hintStackTrace in gNotes:
|
||||
if stackTraceAvailable() and isNil(writelnHook):
|
||||
writeStackTrace()
|
||||
else:
|
||||
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
|
||||
styledMsgWriteln(fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
|
||||
quit 1
|
||||
|
||||
if msg >= fatalMin and msg <= fatalMax:
|
||||
|
|
@ -736,61 +843,85 @@ proc writeContext(lastinfo: TLineInfo) =
|
|||
var info = lastinfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
if msgContext[i] != lastinfo and msgContext[i] != info:
|
||||
msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col+1),
|
||||
getMessageStr(errInstantiationFrom, "")])
|
||||
styledMsgWriteln(styleBright,
|
||||
PosFormat % [toMsgFilename(msgContext[i]),
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col+1)],
|
||||
resetStyle,
|
||||
getMessageStr(errInstantiationFrom, ""))
|
||||
info = msgContext[i]
|
||||
|
||||
proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
|
||||
msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
||||
var frmt: string
|
||||
var
|
||||
title: string
|
||||
color: ForegroundColor
|
||||
kind: string
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = RawErrorFormat
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
of warnMin..warnMax:
|
||||
if optWarns notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = RawWarningFormat
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||
inc(gWarnCounter)
|
||||
of hintMin..hintMax:
|
||||
if optHints notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
frmt = RawHintFormat
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
let s = `%`(frmt, `%`(msgKindToString(msg), args))
|
||||
let s = `%`(msgKindToString(msg), args)
|
||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
||||
msgWriteln(s)
|
||||
if kind != nil:
|
||||
styledMsgWriteln(color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
styledMsgWriteln(color, title, resetStyle, s)
|
||||
handleError(msg, doAbort, s)
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
rawMessage(msg, [arg])
|
||||
|
||||
proc resetAttributes* =
|
||||
if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
|
||||
terminal.resetAttributes(stderr)
|
||||
|
||||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(indent & $info.sourceLine)
|
||||
msgWriteln(indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let frmt = case msg
|
||||
of warnMin..warnMax: PosWarningFormat
|
||||
of hintMin..hintMax: PosHintFormat
|
||||
else: PosErrorFormat
|
||||
result = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col+1), getMessageStr(msg, arg)]
|
||||
let title = case msg
|
||||
of warnMin..warnMax: WarningTitle
|
||||
of hintMin..hintMax: HintTitle
|
||||
else: ErrorTitle
|
||||
result = PosFormat % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col+1)] &
|
||||
title &
|
||||
getMessageStr(msg, arg)
|
||||
|
||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling) =
|
||||
var frmt: string
|
||||
var ignoreMsg = false
|
||||
var
|
||||
title: string
|
||||
color: ForegroundColor
|
||||
kind: string
|
||||
ignoreMsg = false
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(info)
|
||||
frmt = PosErrorFormat
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
# we try to filter error messages so that not two error message
|
||||
# in the same file and line are produced:
|
||||
#ignoreMsg = lastError == info and eh != doAbort
|
||||
|
|
@ -798,20 +929,29 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
|||
of warnMin..warnMax:
|
||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||
if not ignoreMsg: writeContext(info)
|
||||
frmt = PosWarningFormat
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||
inc(gWarnCounter)
|
||||
of hintMin..hintMax:
|
||||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
frmt = PosHintFormat
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
# NOTE: currently line info line numbers start with 1,
|
||||
# but column numbers start with 0, however most editors expect
|
||||
# first column to be 1, so we need to +1 here
|
||||
let s = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col+1), getMessageStr(msg, arg)]
|
||||
let x = PosFormat % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col+1)]
|
||||
let s = getMessageStr(msg, arg)
|
||||
if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
|
||||
msgWriteln(s)
|
||||
if optPrintSurroundingSrc and msg in errMin..errMax:
|
||||
if kind != nil:
|
||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
||||
if msg in errMin..errMax and hintSource in gNotes:
|
||||
info.writeSurroundingSrc
|
||||
handleError(msg, eh, s)
|
||||
|
||||
|
|
@ -882,3 +1022,22 @@ ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
|||
of rCannotOpenFile:
|
||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||
|
||||
proc listWarnings*() =
|
||||
msgWriteln("Warnings:")
|
||||
for warn in warnMin..warnMax:
|
||||
msgWriteln(" [$1] $2" % [
|
||||
if warn in gNotes: "x" else: " ",
|
||||
msgs.WarningsToStr[ord(warn) - ord(warnMin)]
|
||||
])
|
||||
|
||||
proc listHints*() =
|
||||
msgWriteln("Hints:")
|
||||
for hint in hintMin..hintMax:
|
||||
msgWriteln(" [$1] $2" % [
|
||||
if hint in gNotes: "x" else: " ",
|
||||
msgs.HintsToStr[ord(hint) - ord(hintMin)]
|
||||
])
|
||||
|
||||
# enable colors by default on terminals
|
||||
if terminal.isatty(stderr):
|
||||
incl(gGlobalOptions, optUseColors)
|
||||
|
|
|
|||
|
|
@ -17,5 +17,4 @@ define:useStdoutAsStdmsg
|
|||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
symbol:nimfix
|
||||
#gc:markAndSweep
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -16,7 +16,7 @@ when defined(gcc) and defined(windows):
|
|||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
extccomp, strutils, os, osproc, platform, main, parseopt, service,
|
||||
nodejs
|
||||
nodejs, scriptconfig
|
||||
|
||||
when hasTinyCBackend:
|
||||
import tccgen
|
||||
|
|
@ -38,31 +38,44 @@ proc handleCmdLine() =
|
|||
else:
|
||||
# Process command line arguments:
|
||||
processCmdLine(passCmd1, "")
|
||||
if gProjectName != "":
|
||||
if gProjectName == "-":
|
||||
gProjectName = "stdinfile"
|
||||
gProjectFull = "stdinfile"
|
||||
gProjectPath = getCurrentDir()
|
||||
gProjectIsStdin = true
|
||||
elif gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
let p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
gProjectName = p.name
|
||||
else:
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig) # load all config files
|
||||
let scriptFile = gProjectFull.changeFileExt("nims")
|
||||
if fileExists(scriptFile):
|
||||
runNimScript(scriptFile)
|
||||
# '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")
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "")
|
||||
if options.command == "":
|
||||
rawMessage(errNoCommand, command)
|
||||
mainCommand()
|
||||
if gVerbosity >= 2: echo(GC_getStatistics())
|
||||
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
|
||||
#echo(GC_getStatistics())
|
||||
if msgs.gErrorCounter == 0:
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
tccgen.run(commands.arguments)
|
||||
if optRun in gGlobalOptions:
|
||||
if gProjectName == "-":
|
||||
gProjectFull = "stdinfile"
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex: string
|
||||
if options.outFile.len > 0:
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
import parseutils, strutils, strtabs, os, options, msgs, lists
|
||||
|
||||
proc addPath*(path: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, path):
|
||||
proc addPath*(path: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, path):
|
||||
lists.prependStr(options.searchPaths, path)
|
||||
|
||||
proc versionSplitPos(s: string): int =
|
||||
|
|
@ -23,7 +23,7 @@ proc versionSplitPos(s: string): int =
|
|||
const
|
||||
latest = "head"
|
||||
|
||||
proc `<.`(a, b: string): bool =
|
||||
proc `<.`(a, b: string): bool =
|
||||
# wether a has a smaller version than b:
|
||||
if a == latest: return false
|
||||
var i = 0
|
||||
|
|
@ -48,7 +48,7 @@ proc addPackage(packages: StringTableRef, p: string) =
|
|||
let name = p.substr(0, x-1)
|
||||
if x < p.len:
|
||||
let version = p.substr(x+1)
|
||||
if packages[name] <. version:
|
||||
if packages.getOrDefault(name) <. version:
|
||||
packages[name] = version
|
||||
else:
|
||||
packages[name] = latest
|
||||
|
|
@ -60,7 +60,7 @@ iterator chosen(packages: StringTableRef): string =
|
|||
|
||||
proc addNimblePath(p: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, p):
|
||||
if gVerbosity >= 1: message(info, hintPath, p)
|
||||
message(info, hintPath, p)
|
||||
lists.prependStr(options.lazyPaths, p)
|
||||
|
||||
proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
||||
|
|
|
|||
|
|
@ -9,106 +9,106 @@
|
|||
|
||||
# This module handles the reading of the config file.
|
||||
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
options, idents, wordrecg, strtabs
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
# we use Nim's scanner here to save space and work
|
||||
|
||||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||
# simple filter
|
||||
rawGetTok(L, tok)
|
||||
while tok.tokType in {tkComment}: rawGetTok(L, tok)
|
||||
|
||||
|
||||
proc parseExpr(L: var TLexer, tok: var TToken): bool
|
||||
proc parseAtom(L: var TLexer, tok: var TToken): bool =
|
||||
if tok.tokType == tkParLe:
|
||||
proc parseAtom(L: var TLexer, tok: var TToken): bool =
|
||||
if tok.tokType == tkParLe:
|
||||
ppGetTok(L, tok)
|
||||
result = parseExpr(L, tok)
|
||||
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "\')\'")
|
||||
elif tok.ident.id == ord(wNot):
|
||||
elif tok.ident.id == ord(wNot):
|
||||
ppGetTok(L, tok)
|
||||
result = not parseAtom(L, tok)
|
||||
else:
|
||||
result = isDefined(tok.ident)
|
||||
ppGetTok(L, tok)
|
||||
|
||||
proc parseAndExpr(L: var TLexer, tok: var TToken): bool =
|
||||
proc parseAndExpr(L: var TLexer, tok: var TToken): bool =
|
||||
result = parseAtom(L, tok)
|
||||
while tok.ident.id == ord(wAnd):
|
||||
while tok.ident.id == ord(wAnd):
|
||||
ppGetTok(L, tok) # skip "and"
|
||||
var b = parseAtom(L, tok)
|
||||
result = result and b
|
||||
|
||||
proc parseExpr(L: var TLexer, tok: var TToken): bool =
|
||||
proc parseExpr(L: var TLexer, tok: var TToken): bool =
|
||||
result = parseAndExpr(L, tok)
|
||||
while tok.ident.id == ord(wOr):
|
||||
while tok.ident.id == ord(wOr):
|
||||
ppGetTok(L, tok) # skip "or"
|
||||
var b = parseAndExpr(L, tok)
|
||||
result = result or b
|
||||
|
||||
proc evalppIf(L: var TLexer, tok: var TToken): bool =
|
||||
proc evalppIf(L: var TLexer, tok: var TToken): bool =
|
||||
ppGetTok(L, tok) # skip 'if' or 'elif'
|
||||
result = parseExpr(L, tok)
|
||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "\':\'")
|
||||
|
||||
|
||||
var condStack: seq[bool] = @[]
|
||||
|
||||
proc doEnd(L: var TLexer, tok: var TToken) =
|
||||
proc doEnd(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
ppGetTok(L, tok) # skip 'end'
|
||||
setLen(condStack, high(condStack))
|
||||
|
||||
type
|
||||
TJumpDest = enum
|
||||
type
|
||||
TJumpDest = enum
|
||||
jdEndif, jdElseEndif
|
||||
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest)
|
||||
proc doElse(L: var TLexer, tok: var TToken) =
|
||||
proc doElse(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
ppGetTok(L, tok)
|
||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif)
|
||||
|
||||
proc doElif(L: var TLexer, tok: var TToken) =
|
||||
|
||||
proc doElif(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
var res = evalppIf(L, tok)
|
||||
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
|
||||
else: condStack[high(condStack)] = true
|
||||
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||
var nestedIfs = 0
|
||||
while true:
|
||||
while true:
|
||||
if tok.ident != nil and tok.ident.s == "@":
|
||||
ppGetTok(L, tok)
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
of wIf:
|
||||
inc(nestedIfs)
|
||||
of wElse:
|
||||
of wElse:
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElse(L, tok)
|
||||
break
|
||||
of wElif:
|
||||
break
|
||||
of wElif:
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElif(L, tok)
|
||||
break
|
||||
of wEnd:
|
||||
if nestedIfs == 0:
|
||||
break
|
||||
of wEnd:
|
||||
if nestedIfs == 0:
|
||||
doEnd(L, tok)
|
||||
break
|
||||
break
|
||||
if nestedIfs > 0: dec(nestedIfs)
|
||||
else:
|
||||
else:
|
||||
discard
|
||||
ppGetTok(L, tok)
|
||||
elif tok.tokType == tkEof:
|
||||
lexMessage(L, errTokenExpected, "@end")
|
||||
else:
|
||||
ppGetTok(L, tok)
|
||||
|
||||
proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
|
||||
proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
ppGetTok(L, tok) # skip @
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
|
|
@ -126,13 +126,13 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
|||
ppGetTok(L, tok)
|
||||
else:
|
||||
case tok.ident.s.normalize
|
||||
of "putenv":
|
||||
of "putenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
ppGetTok(L, tok)
|
||||
os.putEnv(key, tokToStr(tok))
|
||||
ppGetTok(L, tok)
|
||||
of "prependenv":
|
||||
of "prependenv":
|
||||
ppGetTok(L, tok)
|
||||
var key = tokToStr(tok)
|
||||
ppGetTok(L, tok)
|
||||
|
|
@ -145,17 +145,17 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
|||
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
||||
ppGetTok(L, tok)
|
||||
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
|
||||
|
||||
proc confTok(L: var TLexer, tok: var TToken) =
|
||||
|
||||
proc confTok(L: var TLexer, tok: var TToken) =
|
||||
ppGetTok(L, tok)
|
||||
while tok.ident != nil and tok.ident.s == "@":
|
||||
while tok.ident != nil and tok.ident.s == "@":
|
||||
parseDirective(L, tok) # else: give the token to the parser
|
||||
|
||||
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
|
||||
|
||||
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
|
||||
lexMessage(L, errIdentifierExpected, tokToStr(tok))
|
||||
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
|
||||
confTok(L, tok) # skip unnecessary prefix
|
||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||
|
|
@ -163,13 +163,13 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
|
|||
var s = tokToStr(tok)
|
||||
confTok(L, tok) # skip symbol
|
||||
var val = ""
|
||||
while tok.tokType == tkDot:
|
||||
while tok.tokType == tkDot:
|
||||
add(s, '.')
|
||||
confTok(L, tok)
|
||||
checkSymbol(L, tok)
|
||||
add(s, tokToStr(tok))
|
||||
confTok(L, tok)
|
||||
if tok.tokType == tkBracketLe:
|
||||
if tok.tokType == tkBracketLe:
|
||||
# BUGFIX: val, not s!
|
||||
# BUGFIX: do not copy '['!
|
||||
confTok(L, tok)
|
||||
|
|
@ -180,7 +180,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
|
|||
else: lexMessage(L, errTokenExpected, "']'")
|
||||
add(val, ']')
|
||||
let percent = tok.ident.id == getIdent("%=").id
|
||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||
if len(val) > 0: add(val, ':')
|
||||
confTok(L, tok) # skip ':' or '=' or '%'
|
||||
checkSymbol(L, tok)
|
||||
|
|
@ -211,7 +211,7 @@ proc readConfigFile(filename: string) =
|
|||
while tok.tokType != tkEof: parseAssignment(L, tok)
|
||||
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
|
||||
closeLexer(L)
|
||||
if gVerbosity >= 1: rawMessage(hintConf, filename)
|
||||
rawMessage(hintConf, filename)
|
||||
|
||||
proc getUserConfigPath(filename: string): string =
|
||||
result = joinPath(getConfigDir(), filename)
|
||||
|
|
@ -226,15 +226,7 @@ proc getSystemConfigPath(filename: string): string =
|
|||
if not existsFile(result): result = "/etc/" & filename
|
||||
|
||||
proc loadConfigs*(cfg: string) =
|
||||
# set default value (can be overwritten):
|
||||
if libpath == "":
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir()
|
||||
when defined(posix):
|
||||
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
setDefaultLibpath()
|
||||
|
||||
if optSkipConfigFile notin gGlobalOptions:
|
||||
readConfigFile(getSystemConfigPath(cfg))
|
||||
|
|
@ -246,10 +238,10 @@ proc loadConfigs*(cfg: string) =
|
|||
if optSkipParentConfigFiles notin gGlobalOptions:
|
||||
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
||||
readConfigFile(dir / cfg)
|
||||
|
||||
|
||||
if optSkipProjConfigFile notin gGlobalOptions:
|
||||
readConfigFile(pd / cfg)
|
||||
|
||||
|
||||
if gProjectName.len != 0:
|
||||
# new project wide config file:
|
||||
var projectConfig = changeFileExt(gProjectFull, "nimcfg")
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
## exposes the Nim VM to clients.
|
||||
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
options, nimconf, lists, sem, semdata, llstream, vm
|
||||
|
||||
proc execute*(program: string) =
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@
|
|||
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
|
||||
|
||||
import strutils, os, parseopt
|
||||
import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
|
||||
extccomp, condsyms, lists
|
||||
import compiler/options, compiler/commands, compiler/modules, compiler/sem,
|
||||
compiler/passes, compiler/passaux, compiler/nimfix/pretty,
|
||||
compiler/msgs, compiler/nimconf,
|
||||
compiler/extccomp, compiler/condsyms, compiler/lists
|
||||
|
||||
const Usage = """
|
||||
Nimfix - Tool to patch Nim code
|
||||
|
|
@ -24,7 +26,7 @@ Options:
|
|||
--wholeProject overwrite every processed file.
|
||||
--checkExtern:on|off style check also extern names
|
||||
--styleCheck:on|off|auto performs style checking for identifiers
|
||||
and suggests an alternative spelling;
|
||||
and suggests an alternative spelling;
|
||||
'auto' corrects the spelling.
|
||||
--bestEffort try to fix the code even when there
|
||||
are errors.
|
||||
|
|
@ -48,11 +50,11 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
|||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
gOnlyMainfile = true
|
||||
while true:
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
case p.key.normalize
|
||||
of "overwritefiles":
|
||||
case p.val.normalize
|
||||
|
|
@ -80,7 +82,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
|||
|
||||
proc handleCmdLine() =
|
||||
if paramCount() == 0:
|
||||
stdout.writeln(Usage)
|
||||
stdout.writeLine(Usage)
|
||||
else:
|
||||
processCmdLine(passCmd1, "")
|
||||
if gProjectName != "":
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@
|
|||
## This module implements the code "prettifier". This is part of the toolchain
|
||||
## to convert Nim code into a consistent style.
|
||||
|
||||
import
|
||||
strutils, os, options, ast, astalgo, msgs, ropes, idents,
|
||||
intsets, strtabs, semdata, prettybase
|
||||
import
|
||||
strutils, os, intsets, strtabs
|
||||
|
||||
import compiler/options, compiler/ast, compiler/astalgo, compiler/msgs,
|
||||
compiler/semdata, compiler/nimfix/prettybase, compiler/ropes, compiler/idents
|
||||
|
||||
type
|
||||
StyleCheck* {.pure.} = enum None, Warn, Auto
|
||||
|
|
@ -92,7 +94,7 @@ proc beautifyName(s: string, k: TSymKind): string =
|
|||
|
||||
proc replaceInFile(info: TLineInfo; newName: string) =
|
||||
loadFile(info)
|
||||
|
||||
|
||||
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||
var first = min(info.col.int, line.len)
|
||||
if first < 0: return
|
||||
|
|
@ -100,18 +102,18 @@ proc replaceInFile(info: TLineInfo; newName: string) =
|
|||
while first > 0 and line[first-1] in prettybase.Letters: dec first
|
||||
if first < 0: return
|
||||
if line[first] == '`': inc first
|
||||
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if differ(line, first, last, newName):
|
||||
# last-first+1 != newName.len or
|
||||
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||
# last-first+1 != newName.len or
|
||||
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||
gSourceFiles[info.fileIndex].dirty = true
|
||||
|
||||
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
||||
let beau = beautifyName(s, k)
|
||||
if s != beau:
|
||||
if gStyleCheck == StyleCheck.Auto:
|
||||
if gStyleCheck == StyleCheck.Auto:
|
||||
sym.name = getIdent(beau)
|
||||
replaceInFile(info, beau)
|
||||
else:
|
||||
|
|
@ -137,7 +139,7 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
|
|||
if info.fileIndex < 0: return
|
||||
# we simply convert it to what it looks like in the definition
|
||||
# for consistency
|
||||
|
||||
|
||||
# operators stay as they are:
|
||||
if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, msgs, strutils, idents, lexbase, streams
|
||||
import strutils, lexbase, streams
|
||||
import compiler/ast, compiler/msgs, compiler/idents
|
||||
from os import splitFile
|
||||
|
||||
type
|
||||
|
|
@ -39,7 +40,7 @@ proc loadFile*(info: TLineInfo) =
|
|||
var pos = lex.bufpos
|
||||
while true:
|
||||
case lex.buf[pos]
|
||||
of '\c':
|
||||
of '\c':
|
||||
gSourceFiles[i].newline = "\c\L"
|
||||
break
|
||||
of '\L', '\0':
|
||||
|
|
@ -70,7 +71,7 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
|||
while first > 0 and line[first-1] in Letters: dec first
|
||||
if first < 0: return
|
||||
if line[first] == '`': inc first
|
||||
|
||||
|
||||
let last = first+identLen(line, first)-1
|
||||
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
# handling that exists! Only at line endings checks are necessary
|
||||
# if the buffer needs refilling.
|
||||
|
||||
import
|
||||
import
|
||||
llstream, strutils
|
||||
|
||||
const
|
||||
const
|
||||
Lrz* = ' '
|
||||
Apo* = '\''
|
||||
Tabulator* = '\x09'
|
||||
|
|
@ -27,7 +27,7 @@ const
|
|||
BACKSPACE* = '\x08'
|
||||
VT* = '\x0B'
|
||||
|
||||
const
|
||||
const
|
||||
EndOfFile* = '\0' # end of file marker
|
||||
# A little picture makes everything clear :-)
|
||||
# buf:
|
||||
|
|
@ -36,7 +36,7 @@ const
|
|||
#
|
||||
NewLines* = {CR, LF}
|
||||
|
||||
type
|
||||
type
|
||||
TBaseLexer* = object of RootObj
|
||||
bufpos*: int
|
||||
buf*: cstring
|
||||
|
|
@ -46,9 +46,9 @@ type
|
|||
# private data:
|
||||
sentinel*: int
|
||||
lineStart*: int # index of last line start in buffer
|
||||
|
||||
|
||||
proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
|
||||
|
||||
proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
|
||||
bufLen: int = 8192)
|
||||
# 8K is a reasonable buffer size
|
||||
proc closeBaseLexer*(L: var TBaseLexer)
|
||||
|
|
@ -64,15 +64,15 @@ proc handleLF*(L: var TBaseLexer, pos: int): int
|
|||
# of the LF.
|
||||
# implementation
|
||||
|
||||
const
|
||||
const
|
||||
chrSize = sizeof(char)
|
||||
|
||||
proc closeBaseLexer(L: var TBaseLexer) =
|
||||
proc closeBaseLexer(L: var TBaseLexer) =
|
||||
dealloc(L.buf)
|
||||
llStreamClose(L.stream)
|
||||
|
||||
proc fillBuffer(L: var TBaseLexer) =
|
||||
var
|
||||
proc fillBuffer(L: var TBaseLexer) =
|
||||
var
|
||||
charsRead, toCopy, s: int # all are in characters,
|
||||
# not bytes (in case this
|
||||
# is not the same)
|
||||
|
|
@ -82,68 +82,68 @@ proc fillBuffer(L: var TBaseLexer) =
|
|||
assert(L.sentinel < L.bufLen)
|
||||
toCopy = L.bufLen - L.sentinel - 1
|
||||
assert(toCopy >= 0)
|
||||
if toCopy > 0:
|
||||
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
|
||||
if toCopy > 0:
|
||||
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
|
||||
# "moveMem" handles overlapping regions
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
|
||||
(L.sentinel + 1) * chrSize) div chrSize
|
||||
s = toCopy + charsRead
|
||||
if charsRead < L.sentinel + 1:
|
||||
if charsRead < L.sentinel + 1:
|
||||
L.buf[s] = EndOfFile # set end marker
|
||||
L.sentinel = s
|
||||
else:
|
||||
else:
|
||||
# compute sentinel:
|
||||
dec(s) # BUGFIX (valgrind)
|
||||
while true:
|
||||
while true:
|
||||
assert(s < L.bufLen)
|
||||
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
|
||||
if s >= 0:
|
||||
if s >= 0:
|
||||
# we found an appropriate character for a sentinel:
|
||||
L.sentinel = s
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
# rather than to give up here because the line is too long,
|
||||
# double the buffer's size and try again:
|
||||
oldBufLen = L.bufLen
|
||||
L.bufLen = L.bufLen * 2
|
||||
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
|
||||
assert(L.bufLen - oldBufLen == oldBufLen)
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
|
||||
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
|
||||
oldBufLen * chrSize) div chrSize
|
||||
if charsRead < oldBufLen:
|
||||
if charsRead < oldBufLen:
|
||||
L.buf[oldBufLen + charsRead] = EndOfFile
|
||||
L.sentinel = oldBufLen + charsRead
|
||||
break
|
||||
break
|
||||
s = L.bufLen - 1
|
||||
|
||||
proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
|
||||
proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
|
||||
assert(pos <= L.sentinel)
|
||||
if pos < L.sentinel:
|
||||
if pos < L.sentinel:
|
||||
result = pos + 1 # nothing to do
|
||||
else:
|
||||
else:
|
||||
fillBuffer(L)
|
||||
L.bufpos = 0 # XXX: is this really correct?
|
||||
result = 0
|
||||
L.lineStart = result
|
||||
|
||||
proc handleCR(L: var TBaseLexer, pos: int): int =
|
||||
proc handleCR(L: var TBaseLexer, pos: int): int =
|
||||
assert(L.buf[pos] == CR)
|
||||
inc(L.lineNumber)
|
||||
result = fillBaseLexer(L, pos)
|
||||
if L.buf[result] == LF:
|
||||
if L.buf[result] == LF:
|
||||
result = fillBaseLexer(L, result)
|
||||
|
||||
proc handleLF(L: var TBaseLexer, pos: int): int =
|
||||
proc handleLF(L: var TBaseLexer, pos: int): int =
|
||||
assert(L.buf[pos] == LF)
|
||||
inc(L.lineNumber)
|
||||
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
|
||||
|
||||
proc skipUTF8BOM(L: var TBaseLexer) =
|
||||
|
||||
proc skipUTF8BOM(L: var TBaseLexer) =
|
||||
if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF':
|
||||
inc(L.bufpos, 3)
|
||||
inc(L.lineStart, 3)
|
||||
|
||||
proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
|
||||
proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
|
||||
assert(bufLen > 0)
|
||||
L.bufpos = 0
|
||||
L.bufLen = bufLen
|
||||
|
|
@ -155,15 +155,15 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
|
|||
fillBuffer(L)
|
||||
skipUTF8BOM(L)
|
||||
|
||||
proc getColNumber(L: TBaseLexer, pos: int): int =
|
||||
proc getColNumber(L: TBaseLexer, pos: int): int =
|
||||
result = abs(pos - L.lineStart)
|
||||
|
||||
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||
proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||
result = ""
|
||||
var i = L.lineStart
|
||||
while not (L.buf[i] in {CR, LF, EndOfFile}):
|
||||
while not (L.buf[i] in {CR, LF, EndOfFile}):
|
||||
add(result, L.buf[i])
|
||||
inc(i)
|
||||
result.add("\n")
|
||||
if marker:
|
||||
if marker:
|
||||
result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# this unit handles Nim sets; it implements symbolic sets
|
||||
|
||||
import
|
||||
import
|
||||
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
|
||||
|
||||
proc toBitSet*(s: PNode, b: var TBitSet)
|
||||
|
|
@ -30,17 +30,17 @@ proc equalSets*(a, b: PNode): bool
|
|||
proc cardSet*(s: PNode): BiggestInt
|
||||
# implementation
|
||||
|
||||
proc inSet(s: PNode, elem: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
proc inSet(s: PNode, elem: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
internalError(s.info, "inSet")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
if leValue(s.sons[i].sons[0], elem) and
|
||||
leValue(elem, s.sons[i].sons[1]):
|
||||
leValue(elem, s.sons[i].sons[1]):
|
||||
return true
|
||||
else:
|
||||
if sameValue(s.sons[i], elem):
|
||||
else:
|
||||
if sameValue(s.sons[i], elem):
|
||||
return true
|
||||
result = false
|
||||
|
||||
|
|
@ -58,37 +58,37 @@ proc overlap(a, b: PNode): bool =
|
|||
else:
|
||||
result = sameValue(a, b)
|
||||
|
||||
proc someInSet(s: PNode, a, b: PNode): bool =
|
||||
proc someInSet(s: PNode, a, b: PNode): bool =
|
||||
# checks if some element of a..b is in the set s
|
||||
if s.kind != nkCurly:
|
||||
internalError(s.info, "SomeInSet")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
if leValue(s.sons[i].sons[0], b) and leValue(b, s.sons[i].sons[1]) or
|
||||
leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]):
|
||||
leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]):
|
||||
return true
|
||||
else:
|
||||
else:
|
||||
# a <= elem <= b
|
||||
if leValue(a, s.sons[i]) and leValue(s.sons[i], b):
|
||||
if leValue(a, s.sons[i]) and leValue(s.sons[i], b):
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc toBitSet(s: PNode, b: var TBitSet) =
|
||||
proc toBitSet(s: PNode, b: var TBitSet) =
|
||||
var first, j: BiggestInt
|
||||
first = firstOrd(s.typ.sons[0])
|
||||
bitSetInit(b, int(getSize(s.typ)))
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
j = getOrdValue(s.sons[i].sons[0])
|
||||
while j <= getOrdValue(s.sons[i].sons[1]):
|
||||
while j <= getOrdValue(s.sons[i].sons[1]):
|
||||
bitSetIncl(b, j - first)
|
||||
inc(j)
|
||||
else:
|
||||
else:
|
||||
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
|
||||
|
||||
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
var
|
||||
|
||||
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
var
|
||||
a, b, e, first: BiggestInt # a, b are interval borders
|
||||
elemType: PType
|
||||
n: PNode
|
||||
|
|
@ -98,17 +98,17 @@ proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
|||
result.typ = settype
|
||||
result.info = info
|
||||
e = 0
|
||||
while e < len(s) * ElemSize:
|
||||
if bitSetIn(s, e):
|
||||
while e < len(s) * ElemSize:
|
||||
if bitSetIn(s, e):
|
||||
a = e
|
||||
b = e
|
||||
while true:
|
||||
while true:
|
||||
inc(b)
|
||||
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
|
||||
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
|
||||
dec(b)
|
||||
if a == b:
|
||||
if a == b:
|
||||
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
|
||||
else:
|
||||
else:
|
||||
n = newNodeI(nkRange, info)
|
||||
n.typ = elemType
|
||||
addSon(n, newIntTypeNode(nkIntLit, a + first, elemType))
|
||||
|
|
@ -117,7 +117,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: expr) {.dirty.} =
|
||||
var x, y: TBitSet
|
||||
toBitSet(a, x)
|
||||
toBitSet(b, y)
|
||||
|
|
@ -129,13 +129,13 @@ proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
|
|||
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
|
||||
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
|
||||
|
||||
proc containsSets(a, b: PNode): bool =
|
||||
proc containsSets(a, b: PNode): bool =
|
||||
var x, y: TBitSet
|
||||
toBitSet(a, x)
|
||||
toBitSet(b, y)
|
||||
result = bitSetContains(x, y)
|
||||
|
||||
proc equalSets(a, b: PNode): bool =
|
||||
proc equalSets(a, b: PNode): bool =
|
||||
var x, y: TBitSet
|
||||
toBitSet(a, x)
|
||||
toBitSet(b, y)
|
||||
|
|
@ -147,26 +147,26 @@ proc complement*(a: PNode): PNode =
|
|||
for i in countup(0, high(x)): x[i] = not x[i]
|
||||
result = toTreeSet(x, a.typ, a.info)
|
||||
|
||||
proc cardSet(s: PNode): BiggestInt =
|
||||
proc cardSet(s: PNode): BiggestInt =
|
||||
# here we can do better than converting it into a compact set
|
||||
# we just count the elements directly
|
||||
result = 0
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
result = result + getOrdValue(s.sons[i].sons[1]) -
|
||||
getOrdValue(s.sons[i].sons[0]) + 1
|
||||
else:
|
||||
else:
|
||||
inc(result)
|
||||
|
||||
proc setHasRange(s: PNode): bool =
|
||||
|
||||
proc setHasRange(s: PNode): bool =
|
||||
if s.kind != nkCurly:
|
||||
internalError(s.info, "SetHasRange")
|
||||
return false
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
for i in countup(0, sonsLen(s) - 1):
|
||||
if s.sons[i].kind == nkRange:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc emptyRange(a, b: PNode): bool =
|
||||
proc emptyRange(a, b: PNode): bool =
|
||||
result = not leValue(a, b) # a > b iff not (a <= b)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,192 +7,6 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Nimsuggest is a tool that helps to give editors IDE like capabilities.
|
||||
## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest
|
||||
|
||||
import strutils, os, parseopt, parseUtils
|
||||
import options, commands, modules, sem, passes, passaux, msgs, nimconf,
|
||||
extccomp, condsyms, lists, net, rdstdin
|
||||
|
||||
const Usage = """
|
||||
Nimsuggest - Tool to give every editor IDE like capabilities for Nim
|
||||
Usage:
|
||||
nimsuggest [options] projectfile.nim
|
||||
|
||||
Options:
|
||||
--port:PORT port, by default 6000
|
||||
--address:HOST binds to that address, by default ""
|
||||
--stdin read commands from stdin and write results to
|
||||
stdout instead of using sockets
|
||||
|
||||
The server then listens to the connection and takes line-based commands.
|
||||
|
||||
In addition, all command line options of Nim that do not affect code generation
|
||||
are supported.
|
||||
"""
|
||||
|
||||
var
|
||||
gPort = 6000.Port
|
||||
gAddress = ""
|
||||
gUseStdin: bool
|
||||
|
||||
const
|
||||
seps = {':', ';', ' ', '\t'}
|
||||
Help = "usage: sug|con|def|use file.nim[;dirtyfile.nim]:line:col\n"&
|
||||
"type 'quit' to quit\n" &
|
||||
"type 'debug' to toggle debug mode on/off\n" &
|
||||
"type 'terse' to toggle terse mode on/off"
|
||||
|
||||
proc parseQuoted(cmd: string; outp: var string; start: int): int =
|
||||
var i = start
|
||||
i += skipWhitespace(cmd, i)
|
||||
if cmd[i] == '"':
|
||||
i += parseUntil(cmd, outp, '"', i+1)+2
|
||||
else:
|
||||
i += parseUntil(cmd, outp, seps, i)
|
||||
result = i
|
||||
|
||||
proc action(cmd: string) =
|
||||
template toggle(sw) =
|
||||
if sw in gGlobalOptions:
|
||||
excl(gGlobalOptions, sw)
|
||||
else:
|
||||
incl(gGlobalOptions, sw)
|
||||
return
|
||||
|
||||
template err() =
|
||||
echo Help
|
||||
return
|
||||
|
||||
var opc = ""
|
||||
var i = parseIdent(cmd, opc, 0)
|
||||
case opc.normalize
|
||||
of "sug": gIdeCmd = ideSug
|
||||
of "con": gIdeCmd = ideCon
|
||||
of "def": gIdeCmd = ideDef
|
||||
of "use":
|
||||
modules.resetAllModules()
|
||||
gIdeCmd = ideUse
|
||||
of "quit": quit()
|
||||
of "debug": toggle optIdeDebug
|
||||
of "terse": toggle optIdeTerse
|
||||
else: err()
|
||||
var dirtyfile = ""
|
||||
var orig = ""
|
||||
i = parseQuoted(cmd, orig, i)
|
||||
if cmd[i] == ';':
|
||||
i = parseQuoted(cmd, dirtyfile, i+1)
|
||||
i += skipWhile(cmd, seps, i)
|
||||
var line = -1
|
||||
var col = 0
|
||||
i += parseInt(cmd, line, i)
|
||||
i += skipWhile(cmd, seps, i)
|
||||
i += parseInt(cmd, col, i)
|
||||
|
||||
var isKnownFile = true
|
||||
if orig.len == 0: err()
|
||||
let dirtyIdx = orig.fileInfoIdx(isKnownFile)
|
||||
|
||||
if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
|
||||
else: msgs.setDirtyFile(dirtyIdx, nil)
|
||||
|
||||
resetModule dirtyIdx
|
||||
if dirtyIdx != gProjectMainIdx:
|
||||
resetModule gProjectMainIdx
|
||||
gTrackPos = newLineInfo(dirtyIdx, line, col-1)
|
||||
#echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
|
||||
gErrorCounter = 0
|
||||
if not isKnownFile:
|
||||
compileProject(dirtyIdx)
|
||||
else:
|
||||
compileProject()
|
||||
|
||||
proc serve() =
|
||||
# do not stop after the first error:
|
||||
msgs.gErrorMax = high(int)
|
||||
if gUseStdin:
|
||||
echo Help
|
||||
var line = ""
|
||||
while readLineFromStdin("> ", line):
|
||||
action line
|
||||
echo ""
|
||||
flushFile(stdout)
|
||||
else:
|
||||
var server = newSocket()
|
||||
server.bindAddr(gPort, gAddress)
|
||||
var inp = "".TaintedString
|
||||
server.listen()
|
||||
|
||||
while true:
|
||||
var stdoutSocket = newSocket()
|
||||
msgs.writelnHook = proc (line: string) =
|
||||
stdoutSocket.send(line & "\c\L")
|
||||
|
||||
accept(server, stdoutSocket)
|
||||
|
||||
stdoutSocket.readLine(inp)
|
||||
action inp.string
|
||||
|
||||
stdoutSocket.send("\c\L")
|
||||
stdoutSocket.close()
|
||||
|
||||
proc mainCommand =
|
||||
registerPass verbosePass
|
||||
registerPass semPass
|
||||
gCmd = cmdIdeTools
|
||||
incl gGlobalOptions, optCaasEnabled
|
||||
isServing = true
|
||||
wantMainModule()
|
||||
appendStr(searchPaths, options.libpath)
|
||||
if gProjectFull.len != 0:
|
||||
# current path is always looked first for modules
|
||||
prependStr(searchPaths, gProjectPath)
|
||||
|
||||
serve()
|
||||
|
||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
case p.key.normalize
|
||||
of "port": gPort = parseInt(p.val).Port
|
||||
of "address": gAddress = p.val
|
||||
of "stdin": gUseStdin = true
|
||||
else: processSwitch(pass, p)
|
||||
of cmdArgument:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
# if processArgument(pass, p, argsCount): break
|
||||
|
||||
proc handleCmdLine() =
|
||||
if paramCount() == 0:
|
||||
stdout.writeln(Usage)
|
||||
else:
|
||||
processCmdLine(passCmd1, "")
|
||||
if gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
gProjectName = p.name
|
||||
else:
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "")
|
||||
mainCommand()
|
||||
|
||||
when false:
|
||||
proc quitCalled() {.noconv.} =
|
||||
writeStackTrace()
|
||||
|
||||
addQuitProc(quitCalled)
|
||||
|
||||
condsyms.initDefines()
|
||||
defineSymbol "nimsuggest"
|
||||
handleCmdline()
|
||||
{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# Special configuration file for the Nim project
|
||||
|
||||
gc:markAndSweep
|
||||
|
||||
hint[XDeclaredButNotUsed]:off
|
||||
path:"$projectPath/../.."
|
||||
|
||||
path:"$lib/packages/docutils"
|
||||
path:"../../compiler"
|
||||
|
||||
define:useStdoutAsStdmsg
|
||||
define:nimsuggest
|
||||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
define:booting
|
||||
#define:noDocgen
|
||||
|
|
@ -4,3 +4,5 @@ proc findNodeJs*(): string =
|
|||
result = findExe("nodejs")
|
||||
if result == "":
|
||||
result = findExe("node")
|
||||
if result == "":
|
||||
result = findExe("iojs")
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
# This module contains Nim's version. It is the only place where it needs
|
||||
# to be changed.
|
||||
|
||||
const
|
||||
const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import
|
|||
const
|
||||
hasTinyCBackend* = defined(tinyc)
|
||||
useEffectSystem* = true
|
||||
useWriteTracking* = false
|
||||
hasFFI* = defined(useFFI)
|
||||
newScopeForIf* = true
|
||||
useCaas* = not defined(noCaas)
|
||||
|
|
@ -39,7 +40,7 @@ type # please make sure we have under 32 options
|
|||
TGlobalOption* = enum # **keep binary compatible**
|
||||
gloptNone, optForceFullMake, optDeadCodeElim,
|
||||
optListCmd, optCompileOnly, optNoLinking,
|
||||
optSafeCode, # only allow safe code
|
||||
optReportConceptFailures, # report 'compiles' or 'concept' matching failures
|
||||
optCDebug, # turn on debugging information
|
||||
optGenDynLib, # generate a dynamic library
|
||||
optGenStaticLib, # generate a static library
|
||||
|
|
@ -54,6 +55,7 @@ type # please make sure we have under 32 options
|
|||
optSkipUserConfigFile, # skip the users's config file
|
||||
optSkipParentConfigFiles, # skip parent dir's config files
|
||||
optNoMain, # do not generate a "main" proc
|
||||
optUseColors, # use colors for hints, warnings, and errors
|
||||
optThreads, # support for multi-threading
|
||||
optStdout, # output to stdout
|
||||
optThreadAnalysis, # thread analysis pass
|
||||
|
|
@ -81,13 +83,13 @@ type # please make sure we have under 32 options
|
|||
cmdRun # run the project via TCC backend
|
||||
TStringSeq* = seq[string]
|
||||
TGCMode* = enum # the selected GC
|
||||
gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
|
||||
gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
|
||||
|
||||
TIdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus
|
||||
|
||||
var
|
||||
gIdeCmd*: TIdeCmd
|
||||
gIdeCmd*: IdeCmd
|
||||
|
||||
const
|
||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
|
||||
|
|
@ -126,9 +128,6 @@ template compilationCachePresent*: expr =
|
|||
template optPreserveOrigSource*: expr =
|
||||
optEmbedOrigSrc in gGlobalOptions
|
||||
|
||||
template optPrintSurroundingSrc*: expr =
|
||||
gVerbosity >= 2
|
||||
|
||||
const
|
||||
genSubDir* = "nimcache"
|
||||
NimExt* = "nim"
|
||||
|
|
@ -145,10 +144,12 @@ const
|
|||
var
|
||||
gConfigVars* = newStringTable(modeStyleInsensitive)
|
||||
gDllOverrides = newStringTable(modeCaseInsensitive)
|
||||
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
|
||||
libpath* = ""
|
||||
gProjectName* = "" # holds a name like 'nimrod'
|
||||
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
||||
gProjectFull* = "" # projectPath/projectName
|
||||
gProjectIsStdin* = false # whether we're compiling from stdin
|
||||
gProjectMainIdx*: int32 # the canonical path id of the main module
|
||||
nimcacheDir* = ""
|
||||
command* = "" # the main command (e.g. cc, check, scan, etc)
|
||||
|
|
@ -172,7 +173,7 @@ proc existsConfigVar*(key: string): bool =
|
|||
result = hasKey(gConfigVars, key)
|
||||
|
||||
proc getConfigVar*(key: string): string =
|
||||
result = gConfigVars[key]
|
||||
result = gConfigVars.getOrDefault key
|
||||
|
||||
proc setConfigVar*(key, val: string) =
|
||||
gConfigVars[key] = val
|
||||
|
|
@ -182,8 +183,24 @@ proc getOutFile*(filename, ext: string): string =
|
|||
else: result = changeFileExt(filename, ext)
|
||||
|
||||
proc getPrefixDir*(): string =
|
||||
## gets the application directory
|
||||
result = splitPath(getAppDir()).head
|
||||
## Gets the prefix dir, usually the parent directory where the binary resides.
|
||||
##
|
||||
## This is overrided by some tools (namely nimsuggest) via the ``gPrefixDir``
|
||||
## global.
|
||||
if gPrefixDir != "": result = gPrefixDir
|
||||
else:
|
||||
result = splitPath(getAppDir()).head
|
||||
|
||||
proc setDefaultLibpath*() =
|
||||
# set default value (can be overwritten):
|
||||
if libpath == "":
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir()
|
||||
when defined(posix):
|
||||
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
|
||||
proc canonicalizePath*(path: string): string =
|
||||
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
|
||||
|
|
@ -205,7 +222,7 @@ proc removeTrailingDirSep*(path: string): string =
|
|||
else:
|
||||
result = path
|
||||
|
||||
proc getGeneratedPath: string =
|
||||
proc getNimcacheDir*: string =
|
||||
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
|
||||
genSubDir
|
||||
|
||||
|
|
@ -261,7 +278,7 @@ proc toGeneratedFile*(path, ext: string): string =
|
|||
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||
var (head, tail) = splitPath(path)
|
||||
#if len(head) > 0: head = shortenDir(head & dirSep)
|
||||
result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
|
||||
result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)])
|
||||
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
|
||||
|
||||
when noTimeMachine:
|
||||
|
|
@ -289,14 +306,14 @@ when noTimeMachine:
|
|||
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
var (head, tail) = splitPath(f)
|
||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||
var subdir = getGeneratedPath() # / head
|
||||
var subdir = getNimcacheDir() # / head
|
||||
if createSubDir:
|
||||
try:
|
||||
createDir(subdir)
|
||||
when noTimeMachine:
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
except OSError:
|
||||
writeln(stdout, "cannot create directory: " & subdir)
|
||||
writeLine(stdout, "cannot create directory: " & subdir)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
|
@ -325,13 +342,16 @@ proc rawFindFile2(f: string): string =
|
|||
result = ""
|
||||
|
||||
proc findFile*(f: string): string {.procvar.} =
|
||||
result = f.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile
|
||||
if f.isAbsolute:
|
||||
result = if f.existsFile: f else: ""
|
||||
else:
|
||||
result = f.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.rawFindFile2
|
||||
result = f.toLower.rawFindFile
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile2
|
||||
result = f.rawFindFile2
|
||||
if result.len == 0:
|
||||
result = f.toLower.rawFindFile2
|
||||
|
||||
proc findModule*(modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
|
|
@ -395,3 +415,20 @@ template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
|
|||
template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
|
||||
template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
|
||||
|
||||
proc parseIdeCmd*(s: string): IdeCmd =
|
||||
case s:
|
||||
of "sug": ideSug
|
||||
of "con": ideCon
|
||||
of "def": ideDef
|
||||
of "use": ideUse
|
||||
of "dus": ideDus
|
||||
else: ideNone
|
||||
|
||||
proc `$`*(c: IdeCmd): string =
|
||||
case c:
|
||||
of ideSug: "sug"
|
||||
of ideCon: "con"
|
||||
of ideDef: "def"
|
||||
of ideUse: "use"
|
||||
of ideDus: "dus"
|
||||
of ideNone: "none"
|
||||
|
|
|
|||
|
|
@ -178,13 +178,14 @@ type
|
|||
arDiscriminant, # is a discriminant
|
||||
arStrange # it is a strange beast like 'typedesc[var T]'
|
||||
|
||||
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||
## 'owner' can be nil!
|
||||
result = arNone
|
||||
case n.kind
|
||||
of nkSym:
|
||||
# don't list 'skLet' here:
|
||||
if n.sym.kind in {skVar, skResult, skTemp}:
|
||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
|
||||
else: {skVar, skResult, skTemp}
|
||||
if n.sym.kind in kinds:
|
||||
if owner != nil and owner.id == n.sym.owner.id and
|
||||
sfGlobal notin n.sym.flags:
|
||||
result = arLocalLValue
|
||||
|
|
@ -200,7 +201,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
|||
{tyVar, tyPtr, tyRef}:
|
||||
result = arLValue
|
||||
else:
|
||||
result = isAssignable(owner, n.sons[0])
|
||||
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
|
||||
result = arDiscriminant
|
||||
of nkBracketExpr:
|
||||
|
|
@ -208,23 +209,27 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
|||
{tyVar, tyPtr, tyRef}:
|
||||
result = arLValue
|
||||
else:
|
||||
result = isAssignable(owner, n.sons[0])
|
||||
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
# Object and tuple conversions are still addressable, so we skip them
|
||||
# XXX why is 'tyOpenArray' allowed here?
|
||||
if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
|
||||
{tyOpenArray, tyTuple, tyObject}:
|
||||
result = isAssignable(owner, n.sons[1])
|
||||
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
|
||||
# types that are equal modulo distinction preserve l-value:
|
||||
result = isAssignable(owner, n.sons[1])
|
||||
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||
of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
|
||||
result = arLValue
|
||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||
result = isAssignable(owner, n.sons[0])
|
||||
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||
of nkCallKinds:
|
||||
# builtin slice keeps lvalue-ness:
|
||||
if getMagic(n) == mSlice: result = isAssignable(owner, n.sons[1])
|
||||
if getMagic(n) in {mArrGet, mSlice}:
|
||||
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
if n.typ != nil:
|
||||
result = isAssignable(owner, n.lastSon, isUnsafeAddr)
|
||||
else:
|
||||
discard
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ proc setBaseFlags*(n: PNode, base: TNumericalBase)
|
|||
proc parseSymbol*(p: var TParser, allowNil = false): PNode
|
||||
proc parseTry(p: var TParser; isExpr: bool): PNode
|
||||
proc parseCase(p: var TParser): PNode
|
||||
proc parseStmtPragma(p: var TParser): PNode
|
||||
# implementation
|
||||
|
||||
proc getTok(p: var TParser) =
|
||||
|
|
@ -124,6 +125,9 @@ proc rawSkipComment(p: var TParser, node: PNode) =
|
|||
proc skipComment(p: var TParser, node: PNode) =
|
||||
if p.tok.indent < 0: rawSkipComment(p, node)
|
||||
|
||||
proc flexComment(p: var TParser, node: PNode) =
|
||||
if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node)
|
||||
|
||||
proc skipInd(p: var TParser) =
|
||||
if p.tok.indent >= 0:
|
||||
if not realInd(p): parMessage(p, errInvalidIndentation)
|
||||
|
|
@ -499,10 +503,13 @@ proc parsePar(p: var TParser): PNode =
|
|||
#| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
|
||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
#| | 'when' | 'var' | 'mixin'
|
||||
#| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
|
||||
#| | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
|
||||
#| | (':' expr)? (',' (exprColonEqExpr comma?)*)? )?
|
||||
#| optPar ')'
|
||||
#| par = '(' optInd
|
||||
#| ( &parKeyw complexOrSimpleStmt ^+ ';'
|
||||
#| | ';' complexOrSimpleStmt ^+ ';'
|
||||
#| | pragmaStmt
|
||||
#| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )
|
||||
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
|
||||
#| optPar ')'
|
||||
#
|
||||
# unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
|
||||
# leading ';' could be used to enforce a 'stmt' context ...
|
||||
|
|
@ -521,6 +528,8 @@ proc parsePar(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
optInd(p, result)
|
||||
semiStmtList(p, result)
|
||||
elif p.tok.tokType == tkCurlyDotLe:
|
||||
result.add(parseStmtPragma(p))
|
||||
elif p.tok.tokType != tkParRi:
|
||||
var a = simpleExpr(p)
|
||||
if p.tok.tokType == tkEquals:
|
||||
|
|
@ -881,12 +890,13 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
|||
skipComment(p, result)
|
||||
if realInd(p):
|
||||
withInd(p):
|
||||
skipComment(p, result)
|
||||
rawSkipComment(p, result)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
var a = parseIdentColonEquals(p, {})
|
||||
skipComment(p, a)
|
||||
if p.tok.indent < 0 or p.tok.indent >= p.currInd:
|
||||
rawSkipComment(p, a)
|
||||
addSon(result, a)
|
||||
of tkEof: break
|
||||
else:
|
||||
|
|
@ -1602,6 +1612,7 @@ proc parseEnum(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
addSon(result, ast.emptyNode)
|
||||
optInd(p, result)
|
||||
flexComment(p, result)
|
||||
while true:
|
||||
var a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
|
|
@ -1615,12 +1626,14 @@ proc parseEnum(p: var TParser): PNode =
|
|||
a = newNodeP(nkEnumFieldDef, p)
|
||||
addSon(a, b)
|
||||
addSon(a, parseExpr(p))
|
||||
skipComment(p, a)
|
||||
if p.tok.indent < 0 or p.tok.indent >= p.currInd:
|
||||
rawSkipComment(p, a)
|
||||
if p.tok.tokType == tkComma and p.tok.indent < 0:
|
||||
getTok(p)
|
||||
rawSkipComment(p, a)
|
||||
else:
|
||||
skipComment(p, a)
|
||||
if p.tok.indent < 0 or p.tok.indent >= p.currInd:
|
||||
rawSkipComment(p, a)
|
||||
addSon(result, a)
|
||||
if p.tok.indent >= 0 and p.tok.indent <= p.currInd or
|
||||
p.tok.tokType == tkEof:
|
||||
|
|
@ -1641,7 +1654,7 @@ proc parseObjectWhen(p: var TParser): PNode =
|
|||
addSon(branch, parseExpr(p))
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseObjectPart(p))
|
||||
skipComment(p, branch)
|
||||
flexComment(p, branch)
|
||||
addSon(result, branch)
|
||||
if p.tok.tokType != tkElif: break
|
||||
if p.tok.tokType == tkElse and sameInd(p):
|
||||
|
|
@ -1649,7 +1662,7 @@ proc parseObjectWhen(p: var TParser): PNode =
|
|||
eat(p, tkElse)
|
||||
colcom(p, branch)
|
||||
addSon(branch, parseObjectPart(p))
|
||||
skipComment(p, branch)
|
||||
flexComment(p, branch)
|
||||
addSon(result, branch)
|
||||
|
||||
proc parseObjectCase(p: var TParser): PNode =
|
||||
|
|
@ -1669,7 +1682,7 @@ proc parseObjectCase(p: var TParser): PNode =
|
|||
addSon(a, ast.emptyNode)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType == tkColon: getTok(p)
|
||||
skipComment(p, result)
|
||||
flexComment(p, result)
|
||||
var wasIndented = false
|
||||
let oldInd = p.currInd
|
||||
if realInd(p):
|
||||
|
|
@ -1718,7 +1731,8 @@ proc parseObjectPart(p: var TParser): PNode =
|
|||
result = parseObjectCase(p)
|
||||
of tkSymbol, tkAccent:
|
||||
result = parseIdentColonEquals(p, {withPragma})
|
||||
skipComment(p, result)
|
||||
if p.tok.indent < 0 or p.tok.indent >= p.currInd:
|
||||
rawSkipComment(p, result)
|
||||
of tkNil, tkDiscard:
|
||||
result = newNodeP(nkNilLit, p)
|
||||
getTok(p)
|
||||
|
|
|
|||
|
|
@ -9,38 +9,38 @@
|
|||
|
||||
## implements some little helper passes
|
||||
|
||||
import
|
||||
import
|
||||
strutils, ast, astalgo, passes, msgs, options, idgen
|
||||
|
||||
proc verboseOpen(s: PSym): PPassContext =
|
||||
#MessageOut('compiling ' + s.name.s);
|
||||
result = nil # we don't need a context
|
||||
if gVerbosity > 0: rawMessage(hintProcessing, s.name.s)
|
||||
|
||||
proc verboseProcess(context: PPassContext, n: PNode): PNode =
|
||||
rawMessage(hintProcessing, s.name.s)
|
||||
|
||||
proc verboseProcess(context: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if context != nil: internalError("logpass: context is not nil")
|
||||
if gVerbosity == 3:
|
||||
if gVerbosity == 3:
|
||||
# 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)
|
||||
|
||||
|
||||
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
|
||||
|
||||
proc cleanUp(c: PPassContext, n: PNode): PNode =
|
||||
proc cleanUp(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
# we cannot clean up if dead code elimination is activated
|
||||
if optDeadCodeElim in gGlobalOptions or n == nil: return
|
||||
if optDeadCodeElim in gGlobalOptions or n == nil: return
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i])
|
||||
of nkProcDef, nkMethodDef:
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
of nkProcDef, nkMethodDef:
|
||||
if n.sons[namePos].kind == nkSym:
|
||||
var s = n.sons[namePos].sym
|
||||
if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s):
|
||||
if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s):
|
||||
s.ast.sons[bodyPos] = ast.emptyNode # free the memory
|
||||
else:
|
||||
else:
|
||||
discard
|
||||
|
||||
const cleanupPass* = makePass(process = cleanUp, close = cleanUp)
|
||||
|
|
|
|||
|
|
@ -170,11 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
|||
openPasses(a, module)
|
||||
if stream == nil:
|
||||
let filename = fileIdx.toFullPathConsiderDirty
|
||||
if module.name.s == "-":
|
||||
module.name.s = "stdinfile"
|
||||
s = llStreamOpen(stdin)
|
||||
else:
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
rawMessage(errCannotOpenFile, filename)
|
||||
return
|
||||
|
|
@ -194,8 +190,17 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
|||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
if not processTopLevelStmt(n, a): break
|
||||
|
||||
if sfNoForward in module.flags:
|
||||
# read everything, no streaming possible
|
||||
var sl = newNodeI(nkStmtList, n.info)
|
||||
sl.add n
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
sl.add n
|
||||
discard processTopLevelStmt(sl, a)
|
||||
break
|
||||
elif not processTopLevelStmt(n, a): break
|
||||
closeParsers(p)
|
||||
if s.kind != llsStdIn: break
|
||||
closePasses(a)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ proc inSymChoice(sc, x: PNode): bool =
|
|||
elif sc.kind == nkOpenSymChoice:
|
||||
# same name suffices for open sym choices!
|
||||
result = sc.sons[0].sym.name.id == x.sym.name.id
|
||||
|
||||
|
||||
proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
|
||||
# check param constraints first here as this is quite optimized:
|
||||
if p.constraint != nil:
|
||||
|
|
@ -115,13 +115,13 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
|||
if rpn: arglist.add(n.sons[0])
|
||||
elif n.kind == nkHiddenStdConv and n.sons[1].kind == nkBracket:
|
||||
let n = n.sons[1]
|
||||
for i in 0.. <n.len:
|
||||
for i in 0.. <n.len:
|
||||
if not matchStarAux(c, op, n[i], arglist, rpn): return false
|
||||
elif checkTypes(c, p.sons[2].sym, n):
|
||||
add(arglist, n)
|
||||
else:
|
||||
result = false
|
||||
|
||||
|
||||
if n.kind notin nkCallKinds: return false
|
||||
if matches(c, p.sons[1], n.sons[0]):
|
||||
var arglist = newNodeI(nkArgList, n.info)
|
||||
|
|
@ -130,7 +130,9 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
|
|||
|
||||
proc matches(c: PPatternContext, p, n: PNode): bool =
|
||||
# hidden conversions (?)
|
||||
if isPatternParam(c, p):
|
||||
if nfNoRewrite in n.flags:
|
||||
result = false
|
||||
elif isPatternParam(c, p):
|
||||
result = bindOrCheck(c, p.sym, n)
|
||||
elif n.kind == nkSym and p.kind == nkIdent:
|
||||
result = p.ident.id == n.sym.name.id
|
||||
|
|
@ -149,7 +151,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
|
|||
of "**": result = matchNested(c, p, n, rpn=true)
|
||||
of "~": result = not matches(c, p.sons[1], n)
|
||||
else: internalError(p.info, "invalid pattern")
|
||||
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
|
||||
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
|
||||
# add(a, b)
|
||||
elif p.kind == nkCurlyExpr:
|
||||
if p.sons[1].kind == nkPrefix:
|
||||
|
|
@ -210,7 +212,7 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
|||
if not isNil(c.mapping): c.mapping = nil
|
||||
return false
|
||||
result = true
|
||||
|
||||
|
||||
if p.kind == nkStmtList and n.kind == p.kind and p.len < n.len:
|
||||
let n = flattenStmts(n)
|
||||
# no need to flatten 'p' here as that has already been done
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
import
|
||||
llstream, lexer, parser, idents, strutils, ast, msgs
|
||||
|
||||
proc parseAll*(p: var TParser): PNode =
|
||||
proc parseAll*(p: var TParser): PNode =
|
||||
result = nil
|
||||
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode =
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode =
|
||||
result = nil
|
||||
|
||||
|
|
|
|||
|
|
@ -158,8 +158,8 @@ type
|
|||
TSystemCPU* = enum # Also add CPU for in initialization section and
|
||||
# alias conditionals to condsyms (end of module).
|
||||
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
|
||||
cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
|
||||
cpuJS, cpuNimrodVM, cpuAVR
|
||||
cpuPowerpc64el, cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuMipsel,
|
||||
cpuArm, cpuArm64, cpuJS, cpuNimrodVM, cpuAVR, cpuMSP430
|
||||
|
||||
type
|
||||
TEndian* = enum
|
||||
|
|
@ -175,15 +175,19 @@ const
|
|||
(name: "alpha", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "powerpc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "powerpc64", intSize: 64, endian: bigEndian, floatSize: 64,bit: 64),
|
||||
(name: "powerpc64el", intSize: 64, endian: littleEndian, floatSize: 64,bit: 64),
|
||||
(name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
|
||||
(name: "mipsel", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
|
||||
(name: "arm64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
|
||||
(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: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
|
||||
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
|
||||
|
||||
var
|
||||
targetCPU*, hostCPU*: TSystemCPU
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
## The builtin 'system.locals' implemented as a plugin.
|
||||
|
||||
import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
|
||||
import compiler/plugins, compiler/ast, compiler/astalgo, compiler/magicsys,
|
||||
compiler/lookups, compiler/semdata, compiler/lowerings
|
||||
|
||||
proc semLocals(c: PContext, n: PNode): PNode =
|
||||
var counter = 0
|
||||
|
|
|
|||
|
|
@ -25,19 +25,20 @@ const
|
|||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
|
||||
wOverride, wConstructor}
|
||||
wOverride, wConstructor, wExportNims}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas+{wBase}
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
|
||||
wDelegator}
|
||||
wDelegator, wExportNims}
|
||||
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
||||
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
|
||||
wExportNims}
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wLocks, wGcSafe}
|
||||
exprPragmas* = {wLine, wLocks}
|
||||
wTags, wLocks, wGcSafe, wExportNims}
|
||||
exprPragmas* = {wLine, wLocks, wNoRewrite}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||
|
|
@ -54,15 +55,15 @@ const
|
|||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe}
|
||||
wBorrow, wGcSafe, wExportNims}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wGuard}
|
||||
wImportCpp, wImportObjC, wError, wGuard, wBitsize}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto}
|
||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims}
|
||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims}
|
||||
letPragmas* = varPragmas
|
||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||
|
|
@ -276,7 +277,8 @@ 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[1].kind == nkIdent) and
|
||||
(n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent):
|
||||
(n.sons[0].sons[0].kind == nkIdent):
|
||||
#and (n.sons[1].kind == nkIdent):
|
||||
var nk: TNoteKind
|
||||
case whichKeyword(n.sons[0].sons[0].ident)
|
||||
of wHint:
|
||||
|
|
@ -394,6 +396,8 @@ proc processCompile(c: PContext, n: PNode) =
|
|||
var found = findFile(s)
|
||||
if found == "": found = s
|
||||
var trunc = changeFileExt(found, "")
|
||||
if not isAbsolute(found):
|
||||
found = parentDir(n.info.toFullPath) / found
|
||||
extccomp.addExternalFileToCompile(found)
|
||||
extccomp.addFileToLink(completeCFilePath(trunc, false))
|
||||
|
||||
|
|
@ -590,278 +594,293 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
validPragmas: TSpecialWords): bool =
|
||||
var it = n.sons[i]
|
||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||
if key.kind == nkIdent:
|
||||
var userPragma = strTableGet(c.userPragmas, key.ident)
|
||||
if userPragma != nil:
|
||||
inc c.instCounter
|
||||
if c.instCounter > 100:
|
||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||
pragma(c, sym, userPragma.ast, validPragmas)
|
||||
# ensure the pragma is also remember for generic instantiations in other
|
||||
# modules:
|
||||
n.sons[i] = userPragma.ast
|
||||
dec c.instCounter
|
||||
else:
|
||||
var k = whichKeyword(key.ident)
|
||||
if k in validPragmas:
|
||||
case k
|
||||
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 wImportCompilerProc:
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
|
||||
of wExtern: setExternName(sym, expectStrLit(c, it))
|
||||
of wImmediate:
|
||||
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
|
||||
else: invalidPragma(it)
|
||||
of wDirty:
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||
else: invalidPragma(it)
|
||||
of wImportCpp:
|
||||
processImportCpp(sym, getOptionalStr(c, it, "$1"))
|
||||
of wImportObjC:
|
||||
processImportObjC(sym, getOptionalStr(c, it, "$1"))
|
||||
of wAlign:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var align = expectIntLit(c, it)
|
||||
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.align = align.int16
|
||||
of wSize:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var size = expectIntLit(c, it)
|
||||
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.size = size
|
||||
of wNodecl:
|
||||
noVal(it)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wPure, wAsmNoStackFrame:
|
||||
noVal(it)
|
||||
if sym != nil:
|
||||
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
|
||||
else: incl(sym.flags, sfPure)
|
||||
of wVolatile:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfVolatile)
|
||||
of wRegister:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfRegister)
|
||||
of wThreadVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfThread)
|
||||
of wDeadCodeElim: pragmaDeadCodeElim(c, it)
|
||||
of wNoForward: pragmaNoForward(c, it)
|
||||
of wMagic: processMagic(c, it, sym)
|
||||
of wCompileTime:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wGlobal:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfGlobal)
|
||||
incl(sym.flags, sfPure)
|
||||
of wMerge:
|
||||
# only supported for backwards compat, doesn't do anything anymore
|
||||
noVal(it)
|
||||
of wConstructor:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfConstructor)
|
||||
of wHeader:
|
||||
var lib = getLib(c, libHeader, getStrLitNode(c, it))
|
||||
addToLib(lib, sym)
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.loc.flags, lfHeader)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
|
||||
of wDestructor:
|
||||
sym.flags.incl sfOverriden
|
||||
if sym.name.s.normalize != "destroy":
|
||||
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
|
||||
of wOverride:
|
||||
sym.flags.incl sfOverriden
|
||||
of wNosideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
of wSideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfSideEffect)
|
||||
of wNoreturn:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoReturn)
|
||||
of wDynlib:
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerproc:
|
||||
noVal(it) # compilerproc may not get a string!
|
||||
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||
of wProcVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfProcvar)
|
||||
of wDeprecated:
|
||||
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||
else: incl(c.module.flags, sfDeprecated)
|
||||
of wVarargs:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfVarargs)
|
||||
of wBorrow:
|
||||
if sym.kind == skType:
|
||||
typeBorrow(sym, it)
|
||||
else:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfBorrow)
|
||||
of wFinal:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfFinal)
|
||||
of wInheritable:
|
||||
noVal(it)
|
||||
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfInheritable)
|
||||
of wAcyclic:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfAcyclic)
|
||||
of wShallow:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfShallow)
|
||||
of wThread:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfThread)
|
||||
incl(sym.flags, sfProcvar)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||
of wGcSafe:
|
||||
noVal(it)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(it)
|
||||
of wPacked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfPacked)
|
||||
of wHint: message(it.info, hintUser, expectStrLit(c, it))
|
||||
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
|
||||
of wError:
|
||||
if sym != nil and sym.isRoutine:
|
||||
# This is subtle but correct: the error *statement* is only
|
||||
# allowed for top level statements. Seems to be easier than
|
||||
# distinguishing properly between
|
||||
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
|
||||
noVal(it)
|
||||
incl(sym.flags, sfError)
|
||||
else:
|
||||
localError(it.info, errUser, expectStrLit(c, it))
|
||||
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
|
||||
of wDefine: processDefine(c, it)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processCommonLink(c, it, linkNormal)
|
||||
of wLinksys: processCommonLink(c, it, linkSys)
|
||||
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
|
||||
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
|
||||
of wBreakpoint: pragmaBreakpoint(c, it)
|
||||
of wWatchPoint: pragmaWatchpoint(c, it)
|
||||
of wPush:
|
||||
processPush(c, n, i + 1)
|
||||
result = true
|
||||
of wPop: processPop(c, it)
|
||||
of wPragma:
|
||||
processPragma(c, n, i)
|
||||
result = true
|
||||
of wDiscardable:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfDiscardable)
|
||||
of wNoInit:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfNoInit)
|
||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization,
|
||||
wCallconv,
|
||||
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
||||
wPatterns:
|
||||
if processOption(c, it):
|
||||
# calling conventions (boring...):
|
||||
localError(it.info, errOptionExpected)
|
||||
of FirstCallConv..LastCallConv:
|
||||
assert(sym != nil)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.callConv = wordToCallConv(k)
|
||||
of wEmit: pragmaEmit(c, it)
|
||||
of wUnroll: pragmaUnroll(c, it)
|
||||
of wLinearScanEnd, wComputedGoto: noVal(it)
|
||||
of wEffects:
|
||||
# is later processed in effect analysis:
|
||||
noVal(it)
|
||||
of wIncompleteStruct:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfIncompleteStruct)
|
||||
of wUnchecked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUncheckedArray)
|
||||
of wUnion:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUnion)
|
||||
of wRequiresInit:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfNeedsInit)
|
||||
of wByRef:
|
||||
noVal(it)
|
||||
if sym == nil or sym.typ == nil:
|
||||
if processOption(c, it): localError(it.info, errOptionExpected)
|
||||
else:
|
||||
incl(sym.typ.flags, tfByRef)
|
||||
of wByCopy:
|
||||
noVal(it)
|
||||
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfByCopy)
|
||||
of wInject, wGensym:
|
||||
# We check for errors, but do nothing with these pragmas otherwise
|
||||
# as they are handled directly in 'evalTemplate'.
|
||||
noVal(it)
|
||||
if sym == nil: invalidPragma(it)
|
||||
of wLine: pragmaLine(c, it)
|
||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||
of wLocks:
|
||||
if sym == nil: pragmaLockStmt(c, it)
|
||||
elif sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.lockLevel = pragmaLocks(c, it)
|
||||
of wGuard:
|
||||
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||
of wGoto:
|
||||
if sym == nil or sym.kind notin {skVar, skLet}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.flags.incl sfGoto
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
else:
|
||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||
of wExperimental:
|
||||
noVal(it)
|
||||
if isTopLevel(c):
|
||||
c.module.flags.incl sfExperimental
|
||||
else:
|
||||
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||
if key.kind == nkBracketExpr:
|
||||
processNote(c, it)
|
||||
return
|
||||
let ident = considerQuotedIdent(key)
|
||||
var userPragma = strTableGet(c.userPragmas, ident)
|
||||
if userPragma != nil:
|
||||
inc c.instCounter
|
||||
if c.instCounter > 100:
|
||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||
pragma(c, sym, userPragma.ast, validPragmas)
|
||||
# ensure the pragma is also remember for generic instantiations in other
|
||||
# modules:
|
||||
n.sons[i] = userPragma.ast
|
||||
dec c.instCounter
|
||||
else:
|
||||
var k = whichKeyword(ident)
|
||||
if k in validPragmas:
|
||||
case k
|
||||
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 wImportCompilerProc:
|
||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
|
||||
of wExtern: setExternName(sym, expectStrLit(c, it))
|
||||
of wImmediate:
|
||||
if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
|
||||
else: invalidPragma(it)
|
||||
of wDirty:
|
||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||
else: invalidPragma(it)
|
||||
of wImportCpp:
|
||||
processImportCpp(sym, getOptionalStr(c, it, "$1"))
|
||||
of wImportObjC:
|
||||
processImportObjC(sym, getOptionalStr(c, it, "$1"))
|
||||
of wAlign:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var align = expectIntLit(c, it)
|
||||
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.align = align.int16
|
||||
of wSize:
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
var size = expectIntLit(c, it)
|
||||
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
||||
localError(it.info, errPowerOfTwoExpected)
|
||||
else:
|
||||
sym.typ.size = size
|
||||
of wNodecl:
|
||||
noVal(it)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wPure, wAsmNoStackFrame:
|
||||
noVal(it)
|
||||
if sym != nil:
|
||||
if k == wPure and sym.kind in routineKinds: invalidPragma(it)
|
||||
else: incl(sym.flags, sfPure)
|
||||
of wVolatile:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfVolatile)
|
||||
of wRegister:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfRegister)
|
||||
of wThreadVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfThread)
|
||||
of wDeadCodeElim: pragmaDeadCodeElim(c, it)
|
||||
of wNoForward: pragmaNoForward(c, it)
|
||||
of wMagic: processMagic(c, it, sym)
|
||||
of wCompileTime:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfCompileTime)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
of wGlobal:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfGlobal)
|
||||
incl(sym.flags, sfPure)
|
||||
of wMerge:
|
||||
# only supported for backwards compat, doesn't do anything anymore
|
||||
noVal(it)
|
||||
of wConstructor:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfConstructor)
|
||||
of wHeader:
|
||||
var lib = getLib(c, libHeader, getStrLitNode(c, it))
|
||||
addToLib(lib, sym)
|
||||
incl(sym.flags, sfImportc)
|
||||
incl(sym.loc.flags, lfHeader)
|
||||
incl(sym.loc.flags, lfNoDecl)
|
||||
# implies nodecl, because otherwise header would not make sense
|
||||
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
|
||||
of wDestructor:
|
||||
sym.flags.incl sfOverriden
|
||||
if sym.name.s.normalize != "destroy":
|
||||
localError(n.info, errGenerated, "destructor has to be named 'destroy'")
|
||||
of wOverride:
|
||||
sym.flags.incl sfOverriden
|
||||
of wNosideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoSideEffect)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
|
||||
of wSideeffect:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfSideEffect)
|
||||
of wNoreturn:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfNoReturn)
|
||||
of wDynlib:
|
||||
processDynLib(c, it, sym)
|
||||
of wCompilerproc:
|
||||
noVal(it) # compilerproc may not get a string!
|
||||
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||
of wProcVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfProcvar)
|
||||
of wDeprecated:
|
||||
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||
else: incl(c.module.flags, sfDeprecated)
|
||||
of wVarargs:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfVarargs)
|
||||
of wBorrow:
|
||||
if sym.kind == skType:
|
||||
typeBorrow(sym, it)
|
||||
else:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfBorrow)
|
||||
of wFinal:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfFinal)
|
||||
of wInheritable:
|
||||
noVal(it)
|
||||
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfInheritable)
|
||||
of wAcyclic:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfAcyclic)
|
||||
of wShallow:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfShallow)
|
||||
of wThread:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfThread)
|
||||
incl(sym.flags, sfProcvar)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||
of wGcSafe:
|
||||
noVal(it)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(it)
|
||||
of wPacked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfPacked)
|
||||
of wHint: message(it.info, hintUser, expectStrLit(c, it))
|
||||
of wWarning: message(it.info, warnUser, expectStrLit(c, it))
|
||||
of wError:
|
||||
if sym != nil and sym.isRoutine:
|
||||
# This is subtle but correct: the error *statement* is only
|
||||
# allowed for top level statements. Seems to be easier than
|
||||
# distinguishing properly between
|
||||
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
|
||||
noVal(it)
|
||||
incl(sym.flags, sfError)
|
||||
else:
|
||||
localError(it.info, errUser, expectStrLit(c, it))
|
||||
of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
|
||||
of wDefine: processDefine(c, it)
|
||||
of wUndef: processUndef(c, it)
|
||||
of wCompile: processCompile(c, it)
|
||||
of wLink: processCommonLink(c, it, linkNormal)
|
||||
of wLinksys: processCommonLink(c, it, linkSys)
|
||||
of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
|
||||
of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
|
||||
of wBreakpoint: pragmaBreakpoint(c, it)
|
||||
of wWatchPoint: pragmaWatchpoint(c, it)
|
||||
of wPush:
|
||||
processPush(c, n, i + 1)
|
||||
result = true
|
||||
of wPop: processPop(c, it)
|
||||
of wPragma:
|
||||
processPragma(c, n, i)
|
||||
result = true
|
||||
of wDiscardable:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfDiscardable)
|
||||
of wNoInit:
|
||||
noVal(it)
|
||||
if sym != nil: incl(sym.flags, sfNoInit)
|
||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization,
|
||||
wCallconv,
|
||||
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
||||
wPatterns:
|
||||
if processOption(c, it):
|
||||
# calling conventions (boring...):
|
||||
localError(it.info, errOptionExpected)
|
||||
of FirstCallConv..LastCallConv:
|
||||
assert(sym != nil)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.callConv = wordToCallConv(k)
|
||||
of wEmit: pragmaEmit(c, it)
|
||||
of wUnroll: pragmaUnroll(c, it)
|
||||
of wLinearScanEnd, wComputedGoto: noVal(it)
|
||||
of wEffects:
|
||||
# is later processed in effect analysis:
|
||||
noVal(it)
|
||||
of wIncompleteStruct:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfIncompleteStruct)
|
||||
of wUnchecked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUncheckedArray)
|
||||
of wUnion:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfUnion)
|
||||
of wRequiresInit:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfNeedsInit)
|
||||
of wByRef:
|
||||
noVal(it)
|
||||
if sym == nil or sym.typ == nil:
|
||||
if processOption(c, it): localError(it.info, errOptionExpected)
|
||||
else:
|
||||
incl(sym.typ.flags, tfByRef)
|
||||
of wByCopy:
|
||||
noVal(it)
|
||||
if sym.kind != skType or sym.typ == nil: invalidPragma(it)
|
||||
else: incl(sym.typ.flags, tfByCopy)
|
||||
of wInject, wGensym:
|
||||
# We check for errors, but do nothing with these pragmas otherwise
|
||||
# as they are handled directly in 'evalTemplate'.
|
||||
noVal(it)
|
||||
if sym == nil: invalidPragma(it)
|
||||
of wLine: pragmaLine(c, it)
|
||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||
of wLocks:
|
||||
if sym == nil: pragmaLockStmt(c, it)
|
||||
elif sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.lockLevel = pragmaLocks(c, it)
|
||||
of wBitsize:
|
||||
if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.bitsize = expectIntLit(c, it)
|
||||
of wGuard:
|
||||
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||
of wGoto:
|
||||
if sym == nil or sym.kind notin {skVar, skLet}:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
sym.flags.incl sfGoto
|
||||
of wExportNims:
|
||||
if sym == nil: invalidPragma(it)
|
||||
else: magicsys.registerNimScriptSymbol(sym)
|
||||
of wInjectStmt:
|
||||
if it.kind != nkExprColonExpr:
|
||||
localError(it.info, errExprExpected)
|
||||
else:
|
||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||
of wExperimental:
|
||||
noVal(it)
|
||||
if isTopLevel(c):
|
||||
c.module.flags.incl sfExperimental
|
||||
else:
|
||||
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||
of wNoRewrite:
|
||||
noVal(it)
|
||||
of wBase:
|
||||
noVal(it)
|
||||
sym.flags.incl sfBase
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
else: invalidPragma(it)
|
||||
|
||||
proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
|
||||
validPragmas: TSpecialWords) =
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
|||
discard
|
||||
|
||||
result = nextIdentIter(it, scope.symbols)
|
||||
|
||||
|
||||
return nil
|
||||
|
||||
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
|
|
@ -99,17 +99,17 @@ proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
|||
debug fn.typ
|
||||
debug if result != nil: result.typ else: nil
|
||||
debug if old != nil: old.typ else: nil
|
||||
|
||||
|
||||
when false:
|
||||
proc paramsFitBorrow(child, parent: PNode): bool =
|
||||
proc paramsFitBorrow(child, parent: PNode): bool =
|
||||
var length = sonsLen(child)
|
||||
result = false
|
||||
if length == sonsLen(parent):
|
||||
for i in countup(1, length - 1):
|
||||
if length == sonsLen(parent):
|
||||
for i in countup(1, length - 1):
|
||||
var m = child.sons[i].sym
|
||||
var n = parent.sons[i].sym
|
||||
assert((m.kind == skParam) and (n.kind == skParam))
|
||||
if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return
|
||||
if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return
|
||||
if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
|
||||
dcEqOrDistinctOf): return
|
||||
result = true
|
||||
|
|
@ -120,10 +120,10 @@ when false:
|
|||
var it: TIdentIter
|
||||
for scope in walkScopes(startScope):
|
||||
result = initIdentIter(it, scope.symbols, fn.Name)
|
||||
while result != nil:
|
||||
while result != nil:
|
||||
# watchout! result must not be the same as fn!
|
||||
if (result.Kind == fn.kind) and (result.id != fn.id):
|
||||
if equalGenericParams(result.ast.sons[genericParamsPos],
|
||||
fn.ast.sons[genericParamsPos]):
|
||||
if paramsFitBorrow(fn.typ.n, result.typ.n): return
|
||||
if (result.Kind == fn.kind) and (result.id != fn.id):
|
||||
if equalGenericParams(result.ast.sons[genericParamsPos],
|
||||
fn.ast.sons[genericParamsPos]):
|
||||
if paramsFitBorrow(fn.typ.n, result.typ.n): return
|
||||
result = NextIdentIter(it, scope.symbols)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ type
|
|||
buf*: string
|
||||
pendingNL*: int # negative if not active; else contains the
|
||||
# indentation value
|
||||
pendingWhitespace: int
|
||||
comStack*: seq[PNode] # comment stack
|
||||
flags*: TRenderFlags
|
||||
checkAnon: bool # we're in a context that can contain sfAnon
|
||||
|
|
@ -83,6 +84,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
|||
g.buf = ""
|
||||
g.flags = renderFlags
|
||||
g.pendingNL = -1
|
||||
g.pendingWhitespace = -1
|
||||
g.checkAnon = false
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
|
|
@ -97,12 +99,21 @@ proc addPendingNL(g: var TSrcGen) =
|
|||
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
|
||||
g.lineLen = g.pendingNL
|
||||
g.pendingNL = - 1
|
||||
g.pendingWhitespace = -1
|
||||
elif g.pendingWhitespace >= 0:
|
||||
addTok(g, tkSpaces, spaces(g.pendingWhitespace))
|
||||
g.pendingWhitespace = -1
|
||||
|
||||
proc putNL(g: var TSrcGen, indent: int) =
|
||||
if g.pendingNL >= 0: addPendingNL(g)
|
||||
else: addTok(g, tkSpaces, "\n")
|
||||
g.pendingNL = indent
|
||||
g.lineLen = indent
|
||||
g.pendingWhitespace = -1
|
||||
|
||||
proc previousNL(g: TSrcGen): bool =
|
||||
result = g.pendingNL >= 0 or (g.tokens.len > 0 and
|
||||
g.tokens[^1].kind == tkSpaces)
|
||||
|
||||
proc putNL(g: var TSrcGen) =
|
||||
putNL(g, g.indent)
|
||||
|
|
@ -127,10 +138,13 @@ proc dedent(g: var TSrcGen) =
|
|||
dec(g.lineLen, IndentWidth)
|
||||
|
||||
proc put(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
addPendingNL(g)
|
||||
if len(s) > 0:
|
||||
addTok(g, kind, s)
|
||||
inc(g.lineLen, len(s))
|
||||
if kind != tkSpaces:
|
||||
addPendingNL(g)
|
||||
if len(s) > 0:
|
||||
addTok(g, kind, s)
|
||||
inc(g.lineLen, len(s))
|
||||
else:
|
||||
g.pendingWhitespace = s.len
|
||||
|
||||
proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
|
||||
# use this for tokens over multiple lines.
|
||||
|
|
@ -767,7 +781,8 @@ proc gasm(g: var TSrcGen, n: PNode) =
|
|||
putWithSpace(g, tkAsm, "asm")
|
||||
gsub(g, n.sons[0])
|
||||
gcoms(g)
|
||||
gsub(g, n.sons[1])
|
||||
if n.sons.len > 1:
|
||||
gsub(g, n.sons[1])
|
||||
|
||||
proc gident(g: var TSrcGen, n: PNode) =
|
||||
if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
|
||||
|
|
@ -1195,6 +1210,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
if renderNoPragmas notin g.flags:
|
||||
if g.inPragma <= 0:
|
||||
inc g.inPragma
|
||||
#if not previousNL(g):
|
||||
put(g, tkSpaces, Space)
|
||||
put(g, tkCurlyDotLe, "{.")
|
||||
gcomma(g, n, emptyContext)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,7 +12,7 @@ import strutils
|
|||
|
||||
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.}
|
||||
|
||||
proc toStrMaxPrecision*(f: BiggestFloat): string =
|
||||
proc toStrMaxPrecision*(f: BiggestFloat): string =
|
||||
if f != f:
|
||||
result = "NAN"
|
||||
elif f == 0.0:
|
||||
|
|
@ -21,17 +21,17 @@ proc toStrMaxPrecision*(f: BiggestFloat): string =
|
|||
if f > 0.0: result = "INF"
|
||||
else: result = "-INF"
|
||||
else:
|
||||
var buf: array [0..80, char]
|
||||
c_sprintf(buf, "%#.16e", f)
|
||||
var buf: array [0..80, char]
|
||||
c_sprintf(buf, "%#.16e", f)
|
||||
result = $buf
|
||||
|
||||
proc encodeStr*(s: string, result: var string) =
|
||||
for i in countup(0, len(s) - 1):
|
||||
for i in countup(0, len(s) - 1):
|
||||
case s[i]
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
|
||||
else: add(result, '\\' & toHex(ord(s[i]), 2))
|
||||
|
||||
proc hexChar(c: char, xi: var int) =
|
||||
proc hexChar(c: char, xi: var int) =
|
||||
case c
|
||||
of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
|
||||
of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
|
||||
|
|
@ -41,18 +41,18 @@ proc hexChar(c: char, xi: var int) =
|
|||
proc decodeStr*(s: cstring, pos: var int): string =
|
||||
var i = pos
|
||||
result = ""
|
||||
while true:
|
||||
while true:
|
||||
case s[i]
|
||||
of '\\':
|
||||
of '\\':
|
||||
inc(i, 3)
|
||||
var xi = 0
|
||||
hexChar(s[i-2], xi)
|
||||
hexChar(s[i-1], xi)
|
||||
add(result, chr(xi))
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_':
|
||||
of 'a'..'z', 'A'..'Z', '0'..'9', '_':
|
||||
add(result, s[i])
|
||||
inc(i)
|
||||
else: break
|
||||
else: break
|
||||
pos = i
|
||||
|
||||
const
|
||||
|
|
@ -68,11 +68,11 @@ template encodeIntImpl(self: expr) =
|
|||
var d: char
|
||||
var v = x
|
||||
var rem = v mod 190
|
||||
if rem < 0:
|
||||
if rem < 0:
|
||||
add(result, '-')
|
||||
v = - (v div 190)
|
||||
rem = - rem
|
||||
else:
|
||||
else:
|
||||
v = v div 190
|
||||
var idx = int(rem)
|
||||
if idx < 62: d = chars[idx]
|
||||
|
|
@ -89,11 +89,11 @@ proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
|
|||
encodeVBiggestIntAux(x +% vintDelta, result)
|
||||
# encodeIntImpl(encodeVBiggestInt)
|
||||
|
||||
proc encodeVIntAux(x: int, result: var string) =
|
||||
proc encodeVIntAux(x: int, result: var string) =
|
||||
## encode an int as a variable length base 190 int.
|
||||
encodeIntImpl(encodeVIntAux)
|
||||
|
||||
proc encodeVInt*(x: int, result: var string) =
|
||||
|
||||
proc encodeVInt*(x: int, result: var string) =
|
||||
## encode an int as a variable length base 190 int.
|
||||
encodeVIntAux(x +% vintDelta, result)
|
||||
|
||||
|
|
@ -101,11 +101,11 @@ template decodeIntImpl() =
|
|||
var i = pos
|
||||
var sign = - 1
|
||||
assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
|
||||
if s[i] == '-':
|
||||
if s[i] == '-':
|
||||
inc(i)
|
||||
sign = 1
|
||||
result = 0
|
||||
while true:
|
||||
while true:
|
||||
case s[i]
|
||||
of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
|
||||
of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
|
||||
|
|
@ -116,7 +116,7 @@ template decodeIntImpl() =
|
|||
result = result * sign -% vintDelta
|
||||
pos = i
|
||||
|
||||
proc decodeVInt*(s: cstring, pos: var int): int =
|
||||
proc decodeVInt*(s: cstring, pos: var int): int =
|
||||
decodeIntImpl()
|
||||
|
||||
proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
|
||||
|
|
|
|||
|
|
@ -11,16 +11,17 @@
|
|||
# rod files is a pass, reading of rod files is not! This is why reading and
|
||||
# writing of rod files is split into two different modules.
|
||||
|
||||
import
|
||||
import
|
||||
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
|
||||
condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
|
||||
condsyms, ropes, idents, securehash, rodread, passes, importer, idgen,
|
||||
rodutils
|
||||
|
||||
# implementation
|
||||
|
||||
type
|
||||
type
|
||||
TRodWriter = object of TPassContext
|
||||
module: PSym
|
||||
crc: TCrc32
|
||||
hash: SecureHash
|
||||
options: TOptions
|
||||
defines: string
|
||||
inclDeps: string
|
||||
|
|
@ -38,22 +39,22 @@ type
|
|||
|
||||
PRodWriter = ref TRodWriter
|
||||
|
||||
proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter
|
||||
proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter
|
||||
proc addModDep(w: PRodWriter, dep: string)
|
||||
proc addInclDep(w: PRodWriter, dep: string)
|
||||
proc addInterfaceSym(w: PRodWriter, s: PSym)
|
||||
proc addStmt(w: PRodWriter, n: PNode)
|
||||
proc writeRod(w: PRodWriter)
|
||||
|
||||
proc getDefines(): string =
|
||||
proc getDefines(): string =
|
||||
result = ""
|
||||
for d in definedSymbolNames():
|
||||
if result.len != 0: add(result, " ")
|
||||
add(result, d)
|
||||
|
||||
proc fileIdx(w: PRodWriter, filename: string): int =
|
||||
for i in countup(0, high(w.files)):
|
||||
if w.files[i] == filename:
|
||||
proc fileIdx(w: PRodWriter, filename: string): int =
|
||||
for i in countup(0, high(w.files)):
|
||||
if w.files[i] == filename:
|
||||
return i
|
||||
result = len(w.files)
|
||||
setLen(w.files, result + 1)
|
||||
|
|
@ -62,7 +63,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
|
|||
template filename*(w: PRodWriter): string =
|
||||
w.module.filename
|
||||
|
||||
proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
|
||||
proc newRodWriter(hash: SecureHash, module: PSym): PRodWriter =
|
||||
new(result)
|
||||
result.sstack = @[]
|
||||
result.tstack = @[]
|
||||
|
|
@ -70,7 +71,7 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
|
|||
initIiTable(result.imports.tab)
|
||||
result.index.r = ""
|
||||
result.imports.r = ""
|
||||
result.crc = crc
|
||||
result.hash = hash
|
||||
result.module = module
|
||||
result.defines = getDefines()
|
||||
result.options = options.gOptions
|
||||
|
|
@ -84,19 +85,19 @@ proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
|
|||
result.init = ""
|
||||
result.origFile = module.info.toFilename
|
||||
result.data = newStringOfCap(12_000)
|
||||
|
||||
|
||||
proc addModDep(w: PRodWriter, dep: string) =
|
||||
if w.modDeps.len != 0: add(w.modDeps, ' ')
|
||||
encodeVInt(fileIdx(w, dep), w.modDeps)
|
||||
|
||||
const
|
||||
const
|
||||
rodNL = "\x0A"
|
||||
|
||||
proc addInclDep(w: PRodWriter, dep: string) =
|
||||
var resolved = dep.findModule(w.module.info.toFullPath)
|
||||
encodeVInt(fileIdx(w, dep), w.inclDeps)
|
||||
add(w.inclDeps, " ")
|
||||
encodeVInt(crcFromFile(resolved), w.inclDeps)
|
||||
encodeStr($secureHashFile(resolved), w.inclDeps)
|
||||
add(w.inclDeps, rodNL)
|
||||
|
||||
proc pushType(w: PRodWriter, t: PType) =
|
||||
|
|
@ -109,18 +110,18 @@ proc pushSym(w: PRodWriter, s: PSym) =
|
|||
if iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
w.sstack.add(s)
|
||||
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||
result: var string) =
|
||||
if n == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("()")
|
||||
return
|
||||
result.add('(')
|
||||
encodeVInt(ord(n.kind), result)
|
||||
encodeVInt(ord(n.kind), result)
|
||||
# we do not write comments for now
|
||||
# Line information takes easily 20% or more of the filesize! Therefore we
|
||||
# omit line information if it is the same as the father's line information:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
if fInfo.fileIndex != n.info.fileIndex:
|
||||
result.add('?')
|
||||
encodeVInt(n.info.col, result)
|
||||
result.add(',')
|
||||
|
|
@ -138,7 +139,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
# No need to output the file index, as this is the serialization of one
|
||||
# file.
|
||||
var f = n.flags * PersistentNodeFlags
|
||||
if f != {}:
|
||||
if f != {}:
|
||||
result.add('$')
|
||||
encodeVInt(cast[int32](f), result)
|
||||
if n.typ != nil:
|
||||
|
|
@ -146,16 +147,16 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
encodeVInt(n.typ.id, result)
|
||||
pushType(w, n.typ)
|
||||
case n.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
of nkCharLit..nkInt64Lit:
|
||||
if n.intVal != 0:
|
||||
result.add('!')
|
||||
encodeVBiggestInt(n.intVal, result)
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if n.floatVal != 0.0:
|
||||
result.add('!')
|
||||
encodeStr($n.floatVal, result)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if n.strVal != "":
|
||||
if n.strVal != "":
|
||||
result.add('!')
|
||||
encodeStr(n.strVal, result)
|
||||
of nkIdent:
|
||||
|
|
@ -166,25 +167,25 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
|||
encodeVInt(n.sym.id, result)
|
||||
pushSym(w, n.sym)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
encodeNode(w, n.info, n.sons[i], result)
|
||||
add(result, ')')
|
||||
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||
var oldLen = result.len
|
||||
result.add('<')
|
||||
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
|
||||
if loc.s != low(loc.s):
|
||||
if loc.s != low(loc.s):
|
||||
add(result, '*')
|
||||
encodeVInt(ord(loc.s), result)
|
||||
if loc.flags != {}:
|
||||
if loc.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](loc.flags), result)
|
||||
if loc.t != nil:
|
||||
add(result, '^')
|
||||
encodeVInt(cast[int32](loc.t.id), result)
|
||||
pushType(w, loc.t)
|
||||
if loc.r != nil:
|
||||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr($loc.r, result)
|
||||
if oldLen + 1 == result.len:
|
||||
|
|
@ -192,9 +193,9 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
|||
setLen(result, oldLen)
|
||||
else:
|
||||
add(result, '>')
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
|
||||
proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
if t == nil:
|
||||
# nil nodes have to be stored too:
|
||||
result.add("[]")
|
||||
return
|
||||
|
|
@ -206,38 +207,38 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
|||
encodeVInt(ord(t.kind), result)
|
||||
add(result, '+')
|
||||
encodeVInt(t.id, result)
|
||||
if t.n != nil:
|
||||
if t.n != nil:
|
||||
encodeNode(w, unknownLineInfo(), t.n, result)
|
||||
if t.flags != {}:
|
||||
if t.flags != {}:
|
||||
add(result, '$')
|
||||
encodeVInt(cast[int32](t.flags), result)
|
||||
if t.callConv != low(t.callConv):
|
||||
if t.callConv != low(t.callConv):
|
||||
add(result, '?')
|
||||
encodeVInt(ord(t.callConv), result)
|
||||
if t.owner != nil:
|
||||
if t.owner != nil:
|
||||
add(result, '*')
|
||||
encodeVInt(t.owner.id, result)
|
||||
pushSym(w, t.owner)
|
||||
if t.sym != nil:
|
||||
if t.sym != nil:
|
||||
add(result, '&')
|
||||
encodeVInt(t.sym.id, result)
|
||||
pushSym(w, t.sym)
|
||||
if t.size != - 1:
|
||||
if t.size != - 1:
|
||||
add(result, '/')
|
||||
encodeVBiggestInt(t.size, result)
|
||||
if t.align != 2:
|
||||
if t.align != 2:
|
||||
add(result, '=')
|
||||
encodeVInt(t.align, result)
|
||||
encodeLoc(w, t.loc, result)
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
if t.sons[i] == nil:
|
||||
add(result, "^()")
|
||||
else:
|
||||
add(result, '^')
|
||||
else:
|
||||
add(result, '^')
|
||||
encodeVInt(t.sons[i].id, result)
|
||||
pushType(w, t.sons[i])
|
||||
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||
add(result, '|')
|
||||
encodeVInt(ord(lib.kind), result)
|
||||
add(result, '|')
|
||||
|
|
@ -276,10 +277,10 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
if s.magic != mNone:
|
||||
result.add('@')
|
||||
encodeVInt(ord(s.magic), result)
|
||||
if s.options != w.options:
|
||||
if s.options != w.options:
|
||||
result.add('!')
|
||||
encodeVInt(cast[int32](s.options), result)
|
||||
if s.position != 0:
|
||||
if s.position != 0:
|
||||
result.add('%')
|
||||
encodeVInt(s.position, result)
|
||||
if s.offset != - 1:
|
||||
|
|
@ -307,7 +308,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
if codeAst != nil:
|
||||
# resore the AST:
|
||||
s.ast.sons[codePos] = codeAst
|
||||
|
||||
|
||||
proc addToIndex(w: var TIndex, key, val: int) =
|
||||
if key - w.lastIdxKey == 1:
|
||||
# we do not store a key-diff of 1 to safe space
|
||||
|
|
@ -328,24 +329,25 @@ when debugWrittenIds:
|
|||
|
||||
proc symStack(w: PRodWriter): int =
|
||||
var i = 0
|
||||
while i < len(w.sstack):
|
||||
while i < len(w.sstack):
|
||||
var s = w.sstack[i]
|
||||
if sfForward in s.flags:
|
||||
w.sstack[result] = s
|
||||
inc result
|
||||
elif iiTableGet(w.index.tab, s.id) == InvalidKey:
|
||||
var m = getModule(s)
|
||||
if m == nil: internalError("symStack: module nil: " & s.name.s)
|
||||
if (m.id == w.module.id) or (sfFromGeneric in s.flags):
|
||||
if m == nil and s.kind != skPackage:
|
||||
internalError("symStack: module nil: " & s.name.s)
|
||||
if s.kind == skPackage or m.id == w.module.id or sfFromGeneric in s.flags:
|
||||
# put definition in here
|
||||
var L = w.data.len
|
||||
addToIndex(w.index, s.id, L)
|
||||
addToIndex(w.index, s.id, L)
|
||||
when debugWrittenIds: incl(debugWritten, s.id)
|
||||
encodeSym(w, s, w.data)
|
||||
add(w.data, rodNL)
|
||||
# put into interface section if appropriate:
|
||||
if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
|
||||
s.kind in ExportableSymKinds:
|
||||
if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
|
||||
s.kind in ExportableSymKinds:
|
||||
encodeStr(s.name.s, w.interf)
|
||||
add(w.interf, ' ')
|
||||
encodeVInt(s.id, w.interf)
|
||||
|
|
@ -361,26 +363,26 @@ proc symStack(w: PRodWriter): int =
|
|||
if s.kind == skMethod and sfDispatcher notin s.flags:
|
||||
if w.methods.len != 0: add(w.methods, ' ')
|
||||
encodeVInt(s.id, w.methods)
|
||||
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
|
||||
elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
|
||||
addToIndex(w.imports, s.id, m.id)
|
||||
when debugWrittenIds:
|
||||
if not Contains(debugWritten, s.id):
|
||||
if not contains(debugWritten, s.id):
|
||||
echo(w.filename)
|
||||
debug(s)
|
||||
debug(s.owner)
|
||||
debug(m)
|
||||
InternalError("Symbol referred to but never written")
|
||||
internalError("Symbol referred to but never written")
|
||||
inc(i)
|
||||
setLen(w.sstack, result)
|
||||
|
||||
proc typeStack(w: PRodWriter): int =
|
||||
proc typeStack(w: PRodWriter): int =
|
||||
var i = 0
|
||||
while i < len(w.tstack):
|
||||
while i < len(w.tstack):
|
||||
var t = w.tstack[i]
|
||||
if t.kind == tyForward:
|
||||
w.tstack[result] = t
|
||||
inc result
|
||||
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
elif iiTableGet(w.index.tab, t.id) == InvalidKey:
|
||||
var L = w.data.len
|
||||
addToIndex(w.index, t.id, L)
|
||||
encodeType(w, t, w.data)
|
||||
|
|
@ -400,24 +402,24 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
|
|||
if finalPass and (oldS != 0 or oldT != 0):
|
||||
internalError("could not serialize some forwarded symbols/types")
|
||||
|
||||
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
pushSym(w, s)
|
||||
processStacks(w, false)
|
||||
|
||||
proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
if w == nil: return
|
||||
if s.kind in ExportableSymKinds and
|
||||
{sfExported, sfCompilerProc} * s.flags != {}:
|
||||
proc addInterfaceSym(w: PRodWriter, s: PSym) =
|
||||
if w == nil: return
|
||||
if s.kind in ExportableSymKinds and
|
||||
{sfExported, sfCompilerProc} * s.flags != {}:
|
||||
rawAddInterfaceSym(w, s)
|
||||
|
||||
proc addStmt(w: PRodWriter, n: PNode) =
|
||||
proc addStmt(w: PRodWriter, n: PNode) =
|
||||
encodeVInt(w.data.len, w.init)
|
||||
add(w.init, rodNL)
|
||||
encodeNode(w, unknownLineInfo(), n, w.data)
|
||||
add(w.data, rodNL)
|
||||
processStacks(w, false)
|
||||
|
||||
proc writeRod(w: PRodWriter) =
|
||||
proc writeRod(w: PRodWriter) =
|
||||
processStacks(w, true)
|
||||
var f: File
|
||||
if not open(f, completeGeneratedFilePath(changeFileExt(
|
||||
|
|
@ -438,12 +440,12 @@ proc writeRod(w: PRodWriter) =
|
|||
encodeStr(w.origFile, orig)
|
||||
f.write(orig)
|
||||
f.write(rodNL)
|
||||
|
||||
var crc = "CRC:"
|
||||
encodeVInt(w.crc, crc)
|
||||
f.write(crc)
|
||||
|
||||
var hash = "HASH:"
|
||||
encodeStr($w.hash, hash)
|
||||
f.write(hash)
|
||||
f.write(rodNL)
|
||||
|
||||
|
||||
var options = "OPTIONS:"
|
||||
encodeVInt(cast[int32](w.options), options)
|
||||
f.write(options)
|
||||
|
|
@ -457,31 +459,31 @@ proc writeRod(w: PRodWriter) =
|
|||
var cmd = "CMD:"
|
||||
encodeVInt(cast[int32](gCmd), cmd)
|
||||
f.write(cmd)
|
||||
f.write(rodNL)
|
||||
|
||||
f.write(rodNL)
|
||||
|
||||
f.write("DEFINES:")
|
||||
f.write(w.defines)
|
||||
f.write(rodNL)
|
||||
|
||||
|
||||
var files = "FILES(" & rodNL
|
||||
for i in countup(0, high(w.files)):
|
||||
for i in countup(0, high(w.files)):
|
||||
encodeStr(w.files[i], files)
|
||||
files.add(rodNL)
|
||||
f.write(files)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("INCLUDES(" & rodNL)
|
||||
f.write(w.inclDeps)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("DEPS:")
|
||||
f.write(w.modDeps)
|
||||
f.write(rodNL)
|
||||
|
||||
|
||||
f.write("INTERF(" & rodNL)
|
||||
f.write(w.interf)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("COMPILERPROCS(" & rodNL)
|
||||
f.write(w.compilerProcs)
|
||||
f.write(')' & rodNL)
|
||||
|
|
@ -489,11 +491,11 @@ proc writeRod(w: PRodWriter) =
|
|||
f.write("INDEX(" & rodNL)
|
||||
f.write(w.index.r)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("IMPORTS(" & rodNL)
|
||||
f.write(w.imports.r)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("CONVERTERS:")
|
||||
f.write(w.converters)
|
||||
f.write(rodNL)
|
||||
|
|
@ -501,11 +503,11 @@ proc writeRod(w: PRodWriter) =
|
|||
f.write("METHODS:")
|
||||
f.write(w.methods)
|
||||
f.write(rodNL)
|
||||
|
||||
|
||||
f.write("INIT(" & rodNL)
|
||||
f.write(w.init)
|
||||
f.write(')' & rodNL)
|
||||
|
||||
|
||||
f.write("DATA(" & rodNL)
|
||||
f.write(w.data)
|
||||
f.write(')' & rodNL)
|
||||
|
|
@ -513,23 +515,23 @@ proc writeRod(w: PRodWriter) =
|
|||
# for reading:
|
||||
f.write("\0")
|
||||
f.close()
|
||||
|
||||
|
||||
#echo "interf: ", w.interf.len
|
||||
#echo "index: ", w.index.r.len
|
||||
#echo "init: ", w.init.len
|
||||
#echo "data: ", w.data.len
|
||||
|
||||
proc process(c: PPassContext, n: PNode): PNode =
|
||||
proc process(c: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if c == nil: return
|
||||
if c == nil: return
|
||||
var w = PRodWriter(c)
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
|
||||
#var s = n.sons[namePos].sym
|
||||
#addInterfaceSym(w, s)
|
||||
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef,
|
||||
nkTemplateDef, nkMacroDef:
|
||||
of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef,
|
||||
nkTemplateDef, nkMacroDef:
|
||||
var s = n.sons[namePos].sym
|
||||
if s == nil: internalError(n.info, "rodwrite.process")
|
||||
if n.sons[bodyPos] == nil:
|
||||
|
|
@ -538,17 +540,17 @@ proc process(c: PPassContext, n: PNode): PNode =
|
|||
sfForward notin s.flags:
|
||||
addInterfaceSym(w, s)
|
||||
of nkVarSection, nkLetSection, nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
addInterfaceSym(w, a.sons[0].sym)
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
|
||||
var s = a.sons[0].sym
|
||||
addInterfaceSym(w, s)
|
||||
addInterfaceSym(w, s)
|
||||
# this takes care of enum fields too
|
||||
# Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
|
||||
# type aliasing! Otherwise the same enum symbol would be included
|
||||
|
|
@ -556,29 +558,29 @@ proc process(c: PPassContext, n: PNode): PNode =
|
|||
#
|
||||
# if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin
|
||||
# a := s.typ.n;
|
||||
# for j := 0 to sonsLen(a)-1 do
|
||||
# addInterfaceSym(w, a.sons[j].sym);
|
||||
# end
|
||||
of nkImportStmt:
|
||||
# for j := 0 to sonsLen(a)-1 do
|
||||
# addInterfaceSym(w, a.sons[j].sym);
|
||||
# end
|
||||
of nkImportStmt:
|
||||
for i in countup(0, sonsLen(n) - 1): addModDep(w, getModuleName(n.sons[i]))
|
||||
addStmt(w, n)
|
||||
of nkFromStmt:
|
||||
of nkFromStmt:
|
||||
addModDep(w, getModuleName(n.sons[0]))
|
||||
addStmt(w, n)
|
||||
of nkIncludeStmt:
|
||||
of nkIncludeStmt:
|
||||
for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleName(n.sons[i]))
|
||||
of nkPragma:
|
||||
of nkPragma:
|
||||
addStmt(w, n)
|
||||
else:
|
||||
else:
|
||||
discard
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
if module.id < 0: internalError("rodwrite: module ID not set")
|
||||
var w = newRodWriter(module.fileIdx.getCRC, module)
|
||||
var w = newRodWriter(module.fileIdx.getHash, module)
|
||||
rawAddInterfaceSym(w, module)
|
||||
result = w
|
||||
|
||||
proc myClose(c: PPassContext, n: PNode): PNode =
|
||||
proc myClose(c: PPassContext, n: PNode): PNode =
|
||||
result = process(c, n)
|
||||
var w = PRodWriter(c)
|
||||
writeRod(w)
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ const
|
|||
|
||||
proc equalsFile*(r: Rope, f: File): bool =
|
||||
## returns true if the contents of the file `f` equal `r`.
|
||||
var
|
||||
var
|
||||
buf: array[bufSize, char]
|
||||
bpos = buf.len
|
||||
blen = buf.len
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ proc `|*|`*(a, b: BiggestInt): BiggestInt =
|
|||
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
|
||||
return result
|
||||
|
||||
|
||||
if floatProd >= 0.0:
|
||||
result = high(result)
|
||||
else:
|
||||
|
|
|
|||
146
compiler/scriptconfig.nim
Normal file
146
compiler/scriptconfig.nim
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Implements the new configuration system for Nim. Uses Nim as a scripting
|
||||
## language.
|
||||
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
|
||||
os, times, osproc
|
||||
|
||||
# we support 'cmpIgnoreStyle' natively for efficiency:
|
||||
from strutils import cmpIgnoreStyle
|
||||
|
||||
proc listDirs(a: VmArgs, filter: set[PathComponent]) =
|
||||
let dir = getString(a, 0)
|
||||
var result: seq[string] = @[]
|
||||
for kind, path in walkDir(dir):
|
||||
if kind in filter: result.add path
|
||||
setResult(a, result)
|
||||
|
||||
proc setupVM*(module: PSym; scriptName: string): PEvalContext =
|
||||
# For Nimble we need to export 'setupVM'.
|
||||
result = newCtx(module)
|
||||
result.mode = emRepl
|
||||
registerAdditionalOps(result)
|
||||
|
||||
# captured vars:
|
||||
var errorMsg: string
|
||||
var vthisDir = scriptName.splitFile.dir
|
||||
|
||||
template cbconf(name, body) {.dirty.} =
|
||||
result.registerCallback "stdlib.system." & astToStr(name),
|
||||
proc (a: VmArgs) =
|
||||
body
|
||||
|
||||
template cbos(name, body) {.dirty.} =
|
||||
result.registerCallback "stdlib.system." & astToStr(name),
|
||||
proc (a: VmArgs) =
|
||||
try:
|
||||
body
|
||||
except OSError:
|
||||
errorMsg = getCurrentExceptionMsg()
|
||||
|
||||
# Idea: Treat link to file as a file, but ignore link to directory to prevent
|
||||
# endless recursions out of the box.
|
||||
cbos listFiles:
|
||||
listDirs(a, {pcFile, pcLinkToFile})
|
||||
cbos listDirs:
|
||||
listDirs(a, {pcDir})
|
||||
cbos removeDir:
|
||||
os.removeDir getString(a, 0)
|
||||
cbos removeFile:
|
||||
os.removeFile getString(a, 0)
|
||||
cbos createDir:
|
||||
os.createDir getString(a, 0)
|
||||
cbos getOsError:
|
||||
setResult(a, errorMsg)
|
||||
cbos setCurrentDir:
|
||||
os.setCurrentDir getString(a, 0)
|
||||
cbos getCurrentDir:
|
||||
setResult(a, os.getCurrentDir())
|
||||
cbos moveFile:
|
||||
os.moveFile(getString(a, 0), getString(a, 1))
|
||||
cbos copyFile:
|
||||
os.copyFile(getString(a, 0), getString(a, 1))
|
||||
cbos getLastModificationTime:
|
||||
setResult(a, toSeconds(getLastModificationTime(getString(a, 0))))
|
||||
|
||||
cbos rawExec:
|
||||
setResult(a, osproc.execCmd getString(a, 0))
|
||||
|
||||
cbconf getEnv:
|
||||
setResult(a, os.getEnv(a.getString 0))
|
||||
cbconf existsEnv:
|
||||
setResult(a, os.existsEnv(a.getString 0))
|
||||
cbconf dirExists:
|
||||
setResult(a, os.dirExists(a.getString 0))
|
||||
cbconf fileExists:
|
||||
setResult(a, os.fileExists(a.getString 0))
|
||||
|
||||
cbconf thisDir:
|
||||
setResult(a, vthisDir)
|
||||
cbconf put:
|
||||
options.setConfigVar(getString(a, 0), getString(a, 1))
|
||||
cbconf get:
|
||||
setResult(a, options.getConfigVar(a.getString 0))
|
||||
cbconf exists:
|
||||
setResult(a, options.existsConfigVar(a.getString 0))
|
||||
cbconf nimcacheDir:
|
||||
setResult(a, options.getNimcacheDir())
|
||||
cbconf paramStr:
|
||||
setResult(a, os.paramStr(int a.getInt 0))
|
||||
cbconf paramCount:
|
||||
setResult(a, os.paramCount())
|
||||
cbconf cmpIgnoreStyle:
|
||||
setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
|
||||
cbconf cmpIgnoreCase:
|
||||
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
|
||||
cbconf setCommand:
|
||||
options.command = a.getString 0
|
||||
let arg = a.getString 1
|
||||
if arg.len > 0:
|
||||
gProjectName = arg
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectPath / gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
cbconf getCommand:
|
||||
setResult(a, options.command)
|
||||
cbconf switch:
|
||||
processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo())
|
||||
|
||||
|
||||
proc runNimScript*(scriptName: string) =
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
initDefines()
|
||||
|
||||
defineSymbol("nimscript")
|
||||
defineSymbol("nimconfig")
|
||||
registerPass(semPass)
|
||||
registerPass(evalPass)
|
||||
|
||||
appendStr(searchPaths, options.libpath)
|
||||
|
||||
var m = makeModule(scriptName)
|
||||
incl(m.flags, sfMainModule)
|
||||
vm.globalCtx = setupVM(m, scriptName)
|
||||
|
||||
compileSystemModule()
|
||||
processModule(m, llStreamOpen(scriptName, fmRead), nil)
|
||||
|
||||
# ensure we load 'system.nim' again for the real non-config stuff!
|
||||
resetAllModulesHard()
|
||||
vm.globalCtx = nil
|
||||
# do not remove the defined symbols
|
||||
#initDefines()
|
||||
undefSymbol("nimscript")
|
||||
undefSymbol("nimconfig")
|
||||
|
|
@ -171,11 +171,15 @@ 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
|
||||
|
||||
# like newSymS, but considers gensym'ed symbols
|
||||
if n.kind == nkSym:
|
||||
# and sfGenSym in n.sym.flags:
|
||||
result = n.sym
|
||||
internalAssert result.kind == kind
|
||||
if result.kind != kind:
|
||||
localError(n.info, "cannot use symbol of kind '" &
|
||||
$result.kind & "' as a '" & $kind & "'")
|
||||
# when there is a nested proc inside a template, semtmpl
|
||||
# will assign a wrong owner during the first pass over the
|
||||
# template; we must fix it here: see #909
|
||||
|
|
@ -421,7 +425,11 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
|||
for m in items(rd.methods): methodDef(m, true)
|
||||
|
||||
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = semStmt(c, n)
|
||||
if sfNoForward in c.module.flags:
|
||||
result = semAllTypeSections(c, n)
|
||||
else:
|
||||
result = n
|
||||
result = semStmt(c, result)
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
|||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if c.inCompilesContext > 0:
|
||||
if c.compilesContextId > 0 and optReportConceptFailures notin gGlobalOptions:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.isNil or errors.len == 0:
|
||||
|
|
@ -133,7 +133,10 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
|||
add(candidates, "\n")
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
localError(n.info, errGenerated, result)
|
||||
if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
|
||||
globalError(n.info, errGenerated, result)
|
||||
else:
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||
for scope in walkScopes(c.currentScope):
|
||||
|
|
@ -209,7 +212,10 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
pickBest(callOp)
|
||||
|
||||
if overloadsState == csEmpty and result.state == csEmpty:
|
||||
localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
|
||||
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
||||
localError(n.info, errUndeclaredField, considerQuotedIdent(f).s)
|
||||
else:
|
||||
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f).s)
|
||||
return
|
||||
elif result.state != csMatch:
|
||||
if nfExprCall in n.flags:
|
||||
|
|
@ -232,7 +238,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
internalAssert result.state == csMatch
|
||||
#writeMatches(result)
|
||||
#writeMatches(alt)
|
||||
if c.inCompilesContext > 0:
|
||||
if c.compilesContextId > 0:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
globalError(n.info, errGenerated, "ambiguous call")
|
||||
elif gErrorCounter == 0:
|
||||
|
|
@ -302,8 +308,25 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
|||
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
|
||||
result.typ = newTypeS(x.fauxMatch, c)
|
||||
return
|
||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||
let gp = finalCallee.ast.sons[genericParamsPos]
|
||||
if gp.kind != nkEmpty:
|
||||
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
||||
if x.calleeSym.magic in {mArrGet, mArrPut}:
|
||||
finalCallee = x.calleeSym
|
||||
else:
|
||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||
else:
|
||||
# For macros and templates, the resolved generic params
|
||||
# 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
|
||||
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ type
|
|||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof,
|
||||
efWantStmt, efAllowStmt, efDetermineType,
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
|
||||
efNoProcvarCheck
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
TTypeAttachedOp* = enum
|
||||
|
|
@ -70,7 +71,8 @@ type
|
|||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
||||
inGenericContext*: int # > 0 if we are in a generic type
|
||||
inUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||
inCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
||||
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
|
||||
compilesContextIdGenerator*: int
|
||||
inGenericInst*: int # > 0 if we are instantiating a generic
|
||||
converters*: TSymSeq # sequence of converters
|
||||
patterns*: TSymSeq # sequence of pattern matchers
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ var
|
|||
destructorName = getIdent"destroy_"
|
||||
destructorParam = getIdent"this_"
|
||||
destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
|
||||
rangeDestructorProc*: PSym
|
||||
|
||||
proc instantiateDestructor(c: PContext, typ: PType): PType
|
||||
|
||||
|
|
@ -141,9 +140,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
|||
case t.kind
|
||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
|
||||
if instantiateDestructor(c, t.sons[0]) != nil:
|
||||
if rangeDestructorProc == nil:
|
||||
rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
|
||||
t.destructor = rangeDestructorProc
|
||||
t.destructor = getCompilerProc"nimDestroyRange"
|
||||
return t
|
||||
else:
|
||||
return nil
|
||||
|
|
@ -177,6 +174,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
|
|||
else:
|
||||
return nil
|
||||
|
||||
proc createDestructorCall(c: PContext, s: PSym): PNode =
|
||||
let varTyp = s.typ
|
||||
if varTyp == nil or sfGlobal in s.flags: return
|
||||
let destructableT = instantiateDestructor(c, varTyp)
|
||||
if destructableT != nil:
|
||||
let call = semStmt(c, newNode(nkCall, s.info, @[
|
||||
useSym(destructableT.destructor), useSym(s)]))
|
||||
result = newNode(nkDefer, s.info, @[call])
|
||||
|
||||
proc insertDestructors(c: PContext,
|
||||
varSection: PNode): tuple[outer, inner: PNode] =
|
||||
# Accepts a var or let section.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
elif {efWantStmt, efAllowStmt} * flags != {}:
|
||||
result.typ = newTypeS(tyEmpty, c)
|
||||
result.typ.flags.incl tfVoid
|
||||
else:
|
||||
localError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
|
|
@ -51,7 +52,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
result.typ = errorType(c)
|
||||
else:
|
||||
# XXX tyGenericInst here?
|
||||
semProcvarCheck(c, result)
|
||||
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
semDestructorCheck(c, result, flags)
|
||||
|
||||
|
|
@ -123,6 +124,9 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
return newSymNode(u, n.info)
|
||||
result = newSymNode(s, n.info)
|
||||
of skVar, skLet, skResult, skForVar:
|
||||
if s.magic == mNimvm:
|
||||
localError(n.info, "illegal context for 'nimvm' magic")
|
||||
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
|
|
@ -288,8 +292,6 @@ proc semConv(c: PContext, n: PNode): PNode =
|
|||
|
||||
proc semCast(c: PContext, n: PNode): PNode =
|
||||
## Semantically analyze a casting ("cast[type](param)")
|
||||
if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode)
|
||||
#incl(c.p.owner.flags, sfSideEffect)
|
||||
checkSonsLen(n, 2)
|
||||
result = newNodeI(nkCast, n.info)
|
||||
result.typ = semTypeNode(c, n.sons[0], nil)
|
||||
|
|
@ -448,18 +450,18 @@ proc changeType(n: PNode, newType: PType, check: bool) =
|
|||
let tup = newType.skipTypes({tyGenericInst})
|
||||
if tup.kind != tyTuple:
|
||||
if tup.kind == tyObject: return
|
||||
internalError(n.info, "changeType: no tuple type for constructor")
|
||||
globalError(n.info, "no tuple type for constructor")
|
||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
# named tuple?
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = n.sons[i].sons[0]
|
||||
if m.kind != nkSym:
|
||||
internalError(m.info, "changeType(): invalid tuple constr")
|
||||
globalError(m.info, "invalid tuple constructor")
|
||||
return
|
||||
if tup.n != nil:
|
||||
var f = getSymFromList(tup.n, m.sym.name)
|
||||
if f == nil:
|
||||
internalError(m.info, "changeType(): invalid identifier")
|
||||
globalError(m.info, "unknown identifier: " & m.sym.name.s)
|
||||
return
|
||||
changeType(n.sons[i].sons[1], f.typ, check)
|
||||
else:
|
||||
|
|
@ -474,7 +476,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
|
|||
addSon(a, m)
|
||||
changeType(m, tup.sons[i], check)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if check:
|
||||
if check and n.kind != nkUInt64Lit:
|
||||
let value = n.intVal
|
||||
if value < firstOrd(newType) or value > lastOrd(newType):
|
||||
localError(n.info, errGenerated, "cannot convert " & $value &
|
||||
|
|
@ -596,8 +598,8 @@ proc skipObjConv(n: PNode): PNode =
|
|||
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
|
||||
else: result = n
|
||||
|
||||
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||
result = parampatterns.isAssignable(c.p.owner, n)
|
||||
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
|
||||
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
|
||||
|
|
@ -805,6 +807,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
return semExpr(c, result, flags)
|
||||
else:
|
||||
n.sons[0] = semExpr(c, n.sons[0])
|
||||
let t = n.sons[0].typ
|
||||
if t != nil and t.kind == tyVar:
|
||||
n.sons[0] = newDeref(n.sons[0])
|
||||
let nOrig = n.copyTree
|
||||
semOpAux(c, n)
|
||||
var t: PType = nil
|
||||
|
|
@ -814,7 +819,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# This is a proc variable, apply normal overload resolution
|
||||
let m = resolveIndirectCall(c, n, nOrig, t)
|
||||
if m.state != csMatch:
|
||||
if c.inCompilesContext > 0:
|
||||
if c.compilesContextId > 0:
|
||||
# speed up error generation:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
return emptyNode
|
||||
|
|
@ -1152,7 +1157,7 @@ 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])
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck})
|
||||
let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
case arr.kind
|
||||
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
|
||||
|
|
@ -1192,7 +1197,17 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
localError(n.info, errIndexTypesDoNotMatch)
|
||||
result = n
|
||||
else:
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
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}+skIterators:
|
||||
# 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)
|
||||
else:
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
|
||||
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
|
|
@ -1246,7 +1261,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
|||
template resultTypeIsInferrable(typ: PType): expr =
|
||||
typ.isMetaType and typ.kind != tyTypeDesc
|
||||
|
||||
proc semAsgn(c: PContext, n: PNode): PNode =
|
||||
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
checkSonsLen(n, 2)
|
||||
var a = n.sons[0]
|
||||
case a.kind
|
||||
|
|
@ -1269,18 +1284,29 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
|||
# --> `[]=`(a, i, x)
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
a = semSubscript(c, a, {efLValue})
|
||||
if a == nil:
|
||||
if a == nil and mode != noOverloadedSubscript:
|
||||
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
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
of nkCurlyExpr:
|
||||
# a{i} = x --> `{}=`(a, i, x)
|
||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
|
||||
add(result, n[1])
|
||||
return semExprNoType(c, result)
|
||||
of nkPar:
|
||||
if a.len >= 2:
|
||||
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
|
||||
# that overloading of the assignment operator still works. Usually we
|
||||
# prefer to do these rewritings in transf.nim:
|
||||
return semStmt(c, lowerTupleUnpackingForAsgn(n, c.p.owner))
|
||||
else:
|
||||
a = semExprWithType(c, a, {efLValue})
|
||||
else:
|
||||
a = semExprWithType(c, a, {efLValue})
|
||||
n.sons[0] = a
|
||||
|
|
@ -1311,7 +1337,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
|||
typeMismatch(n, lhs.typ, rhs.typ)
|
||||
|
||||
n.sons[1] = fitNode(c, le, rhs)
|
||||
if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
|
||||
if tfHasAsgn in lhs.typ.flags and not lhsIsResult and
|
||||
mode != noOverloadedAsgn:
|
||||
return overloadedAsgn(c, lhs, n.sons[1])
|
||||
|
||||
fixAbstractType(c, n)
|
||||
|
|
@ -1369,7 +1396,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
|||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
||||
if isEmptyType(result.typ):
|
||||
# we inferred a 'void' return type:
|
||||
c.p.resultSym.typ = nil
|
||||
c.p.resultSym.typ = errorType(c)
|
||||
c.p.owner.typ.sons[0] = nil
|
||||
else:
|
||||
localError(c.p.resultSym.info, errCannotInferReturnType)
|
||||
|
|
@ -1610,7 +1637,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
# watch out, hacks ahead:
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
let oldErrorMax = msgs.gErrorMax
|
||||
inc c.inCompilesContext
|
||||
let oldCompilesId = c.compilesContextId
|
||||
inc c.compilesContextIdGenerator
|
||||
c.compilesContextId = c.compilesContextIdGenerator
|
||||
# do not halt after first error:
|
||||
msgs.gErrorMax = high(int)
|
||||
|
||||
|
|
@ -1628,12 +1657,15 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
let oldInGenericInst = c.inGenericInst
|
||||
let oldProcCon = c.p
|
||||
c.generics = @[]
|
||||
var err: string
|
||||
try:
|
||||
result = semExpr(c, n, flags)
|
||||
if msgs.gErrorCounter != oldErrorCount: result = nil
|
||||
except ERecoverableError:
|
||||
discard
|
||||
if optReportConceptFailures in gGlobalOptions:
|
||||
err = getCurrentExceptionMsg()
|
||||
# undo symbol table changes (as far as it's possible):
|
||||
c.compilesContextId = oldCompilesId
|
||||
c.generics = oldGenerics
|
||||
c.inGenericContext = oldInGenericContext
|
||||
c.inUnrolledContext = oldInUnrolledContext
|
||||
|
|
@ -1642,10 +1674,11 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
msgs.setInfoContextLen(oldContextLen)
|
||||
setLen(gOwners, oldOwnerLen)
|
||||
c.currentScope = oldScope
|
||||
dec c.inCompilesContext
|
||||
errorOutputs = oldErrorOutputs
|
||||
msgs.gErrorCounter = oldErrorCount
|
||||
msgs.gErrorMax = oldErrorMax
|
||||
if optReportConceptFailures in gGlobalOptions and not err.isNil:
|
||||
localError(n.info, err)
|
||||
|
||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
|
|
@ -1699,10 +1732,13 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
case s.magic # magics that need special treatment
|
||||
of mAddr:
|
||||
checkSonsLen(n, 2)
|
||||
result = semAddr(c, n.sons[1])
|
||||
result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
|
||||
of mTypeOf:
|
||||
checkSonsLen(n, 2)
|
||||
result = semTypeOf(c, n.sons[1])
|
||||
#of mArrGet: result = semArrGet(c, n, flags)
|
||||
#of mArrPut: result = semArrPut(c, n, flags)
|
||||
#of mAsgn: result = semAsgnOpr(c, n)
|
||||
of mDefined: result = semDefined(c, setMs(n, s), false)
|
||||
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
||||
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
||||
|
|
@ -1719,6 +1755,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
result.typ = getSysType(tyString)
|
||||
of mParallel:
|
||||
if not experimentalMode(c):
|
||||
localError(n.info, "use the {.experimental.} pragma to enable 'parallel'")
|
||||
result = setMs(n, s)
|
||||
var x = n.lastSon
|
||||
if x.kind == nkDo: x = x.sons[bodyPos]
|
||||
|
|
@ -1727,13 +1765,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
dec c.inParallelStmt
|
||||
of mSpawn:
|
||||
result = setMs(n, s)
|
||||
result.sons[1] = semExpr(c, n.sons[1])
|
||||
if not result[1].typ.isEmptyType:
|
||||
if spawnResult(result[1].typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
result.typ = createFlowVar(c, result[1].typ, n.info)
|
||||
for i in 1 .. <n.len:
|
||||
result.sons[i] = semExpr(c, n.sons[i])
|
||||
let typ = result[^1].typ
|
||||
if not typ.isEmptyType:
|
||||
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
|
||||
result.typ = createFlowVar(c, typ, n.info)
|
||||
else:
|
||||
result.typ = result[1].typ
|
||||
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
||||
result.typ = typ
|
||||
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
|
||||
else:
|
||||
result.add emptyNode
|
||||
of mProcCall:
|
||||
result = setMs(n, s)
|
||||
result.sons[1] = semExpr(c, n.sons[1])
|
||||
|
|
@ -1749,22 +1791,44 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
|||
if semCheck: result = semStmt(c, e) # do not open a new scope!
|
||||
else: result = e
|
||||
|
||||
# Check if the node is "when nimvm"
|
||||
# when nimvm:
|
||||
# ...
|
||||
# else:
|
||||
# ...
|
||||
var whenNimvm = false
|
||||
if n.sons.len == 2 and n.sons[0].kind == nkElifBranch and
|
||||
n.sons[1].kind == nkElse:
|
||||
let exprNode = n.sons[0].sons[0]
|
||||
if exprNode.kind == nkIdent:
|
||||
whenNimvm = lookUp(c, exprNode).magic == mNimvm
|
||||
elif exprNode.kind == nkSym:
|
||||
whenNimvm = exprNode.sym.magic == mNimvm
|
||||
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifBranch, nkElifExpr:
|
||||
checkSonsLen(it, 2)
|
||||
var e = semConstExpr(c, it.sons[0])
|
||||
if e.kind != nkIntLit:
|
||||
# can happen for cascading errors, assume false
|
||||
# InternalError(n.info, "semWhen")
|
||||
discard
|
||||
elif e.intVal != 0 and result == nil:
|
||||
setResult(it.sons[1])
|
||||
if whenNimvm:
|
||||
if semCheck:
|
||||
it.sons[1] = semStmt(c, it.sons[1])
|
||||
result = n # when nimvm is not elimited until codegen
|
||||
else:
|
||||
var e = semConstExpr(c, it.sons[0])
|
||||
if e.kind != nkIntLit:
|
||||
# can happen for cascading errors, assume false
|
||||
# InternalError(n.info, "semWhen")
|
||||
discard
|
||||
elif e.intVal != 0 and result == nil:
|
||||
setResult(it.sons[1])
|
||||
of nkElse, nkElseExpr:
|
||||
checkSonsLen(it, 1)
|
||||
if result == nil:
|
||||
setResult(it.sons[0])
|
||||
if result == nil or whenNimvm:
|
||||
if semCheck:
|
||||
it.sons[0] = semStmt(c, it.sons[0])
|
||||
if result == nil:
|
||||
result = it.sons[0]
|
||||
else: illFormedAst(n)
|
||||
if result == nil:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
|
@ -2026,6 +2090,19 @@ proc semExport(c: PContext, n: PNode): PNode =
|
|||
c.module.ast.add x
|
||||
result = n
|
||||
|
||||
proc shouldBeBracketExpr(n: PNode): bool =
|
||||
assert n.kind in nkCallKinds
|
||||
let a = n.sons[0]
|
||||
if a.kind in nkCallKinds:
|
||||
let b = a[0]
|
||||
if b.kind in nkSymChoices:
|
||||
for i in 0..<b.len:
|
||||
if b[i].sym.magic == mArrGet:
|
||||
let be = newNodeI(nkBracketExpr, n.info)
|
||||
for i in 1..<a.len: be.add(a[i])
|
||||
n.sons[0] = be
|
||||
return true
|
||||
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
for i in 1 .. <n.len:
|
||||
n[i].typ = semTypeNode(c, n[i], nil)
|
||||
|
|
@ -2133,7 +2210,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
else:
|
||||
#liMessage(n.info, warnUser, renderTree(n));
|
||||
result = semIndirectOp(c, n, flags)
|
||||
elif n[0].kind == nkBracketExpr and isSymChoice(n[0][0]):
|
||||
elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
|
||||
isSymChoice(n[0][0]):
|
||||
# indirectOp can deal with explicit instantiations; the fixes
|
||||
# the 'newSeq[T](x)' bug
|
||||
setGenericParams(c, n.sons[0])
|
||||
|
|
@ -2147,19 +2225,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
result = semWhen(c, n, true)
|
||||
else:
|
||||
result = semWhen(c, n, false)
|
||||
result = semExpr(c, result, flags)
|
||||
if result == n:
|
||||
# This is a "when nimvm" stmt.
|
||||
result = semWhen(c, n, true)
|
||||
else:
|
||||
result = semExpr(c, result, flags)
|
||||
of nkBracketExpr:
|
||||
checkMinSonsLen(n, 1)
|
||||
var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
|
||||
if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or
|
||||
n[0].kind in nkSymChoices:
|
||||
# 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 in {skType}:
|
||||
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
|
||||
else:
|
||||
result = semArrayAccess(c, n, flags)
|
||||
result = semArrayAccess(c, n, flags)
|
||||
of nkCurlyExpr:
|
||||
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
|
||||
of nkPragmaExpr:
|
||||
|
|
@ -2254,7 +2327,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkStaticStmt:
|
||||
result = semStaticStmt(c, n)
|
||||
of nkDefer:
|
||||
localError(n.info, errGenerated, "'defer' not allowed in this context")
|
||||
n.sons[0] = semExpr(c, n.sons[0])
|
||||
if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
|
||||
localError(n.info, errGenerated, "'defer' takes a 'void' expression")
|
||||
#localError(n.info, errGenerated, "'defer' not allowed in this context")
|
||||
else:
|
||||
localError(n.info, errInvalidExpressionX,
|
||||
renderTree(n, {renderNoComments}))
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
|
|||
let L = forLoop.len
|
||||
let call = forLoop.sons[L-2]
|
||||
if call.len > 2:
|
||||
localError(forLoop.info, errGenerated,
|
||||
localError(forLoop.info, errGenerated,
|
||||
"parallel 'fields' iterator does not work for 'case' objects")
|
||||
return
|
||||
# iterate over the selector:
|
||||
|
|
@ -106,7 +106,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
|||
# a 'while true: stmt; break' loop ...
|
||||
result = newNodeI(nkWhileStmt, n.info, 2)
|
||||
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
|
||||
if trueSymbol == nil:
|
||||
if trueSymbol == nil:
|
||||
localError(n.info, errSystemNeeds, "true")
|
||||
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
|
||||
trueSymbol.typ = getSysType(tyBool)
|
||||
|
|
@ -114,13 +114,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
|||
result.sons[0] = newSymNode(trueSymbol, n.info)
|
||||
var stmts = newNodeI(nkStmtList, n.info)
|
||||
result.sons[1] = stmts
|
||||
|
||||
|
||||
var length = sonsLen(n)
|
||||
var call = n.sons[length-2]
|
||||
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
||||
localError(n.info, errWrongNumberOfVariables)
|
||||
return result
|
||||
|
||||
|
||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
|
||||
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
||||
localError(n.info, errGenerated, "no object or tuple type")
|
||||
|
|
@ -129,7 +129,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
|||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
|
||||
if not sameType(tupleTypeA, tupleTypeB):
|
||||
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
|
||||
|
||||
|
||||
inc(c.p.nestedLoopCounter)
|
||||
if tupleTypeA.kind == tyTuple:
|
||||
var loopBody = n.sons[length-1]
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
else:
|
||||
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
|
||||
abs(getFloat(a.n.sons[0])))
|
||||
of mAbsI, mAbsI64:
|
||||
of mAbsI:
|
||||
let a = n.sons[1].typ
|
||||
if isIntRange(a):
|
||||
if a.n[0].intVal <= 0:
|
||||
|
|
@ -200,13 +200,13 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
if isIntRange(a) and isIntLit(b):
|
||||
result = makeRange(a, pickMinInt(n.sons[1]) |-| pickMinInt(n.sons[2]),
|
||||
pickMaxInt(n.sons[1]) |-| pickMaxInt(n.sons[2]))
|
||||
of mAddI, mAddI64, mAddU:
|
||||
of mAddI, mAddU:
|
||||
commutativeOp(`|+|`)
|
||||
of mMulI, mMulI64, mMulU:
|
||||
of mMulI, mMulU:
|
||||
commutativeOp(`|*|`)
|
||||
of mSubI, mSubI64, mSubU:
|
||||
of mSubI, mSubU:
|
||||
binaryOp(`|-|`)
|
||||
of mBitandI, mBitandI64:
|
||||
of mBitandI:
|
||||
# since uint64 is still not even valid for 'range' (since it's no ordinal
|
||||
# yet), we exclude it from the list (see bug #1638) for now:
|
||||
var a = n.sons[1]
|
||||
|
|
@ -225,7 +225,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
result = makeRange(a.typ, 0, b.intVal-1)
|
||||
else:
|
||||
result = makeRange(a.typ, b.intVal+1, 0)
|
||||
of mModI, mModI64:
|
||||
of mModI:
|
||||
# so ... if you ever wondered about modulo's signedness; this defines it:
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
|
|
@ -234,7 +234,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
result = makeRange(a.typ, -(b.intVal-1), b.intVal-1)
|
||||
else:
|
||||
result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
|
||||
of mDivI, mDivI64, mDivU:
|
||||
of mDivI, mDivU:
|
||||
binaryOp(`|div|`)
|
||||
of mMinI:
|
||||
commutativeOp(min)
|
||||
|
|
@ -243,8 +243,8 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
else: discard
|
||||
|
||||
discard """
|
||||
mShlI, mShlI64,
|
||||
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
|
||||
mShlI,
|
||||
mShrI, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
|
||||
"""
|
||||
|
||||
proc evalIs(n, a: PNode): PNode =
|
||||
|
|
@ -285,7 +285,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
|
||||
of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
|
||||
of 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)
|
||||
|
|
@ -298,7 +298,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
|
||||
of mAbsI, mAbsI64:
|
||||
of mAbsI:
|
||||
if getInt(a) >= 0: result = a
|
||||
else: result = newIntNodeT(- getInt(a), n)
|
||||
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
|
||||
|
|
@ -307,19 +307,19 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
|
||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
|
||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
|
||||
of mUnaryLt: result = newIntNodeT(getOrdValue(a) - 1, n)
|
||||
of mSucc: result = newIntNodeT(getOrdValue(a) + getInt(b), n)
|
||||
of mPred: result = newIntNodeT(getOrdValue(a) - getInt(b), n)
|
||||
of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
|
||||
of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
|
||||
of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
|
||||
of mUnaryLt: result = newIntNodeT(getOrdValue(a) |-| 1, n)
|
||||
of mSucc: result = newIntNodeT(getOrdValue(a) |+| getInt(b), n)
|
||||
of mPred: result = newIntNodeT(getOrdValue(a) |-| getInt(b), n)
|
||||
of mAddI: result = newIntNodeT(getInt(a) |+| getInt(b), n)
|
||||
of mSubI: result = newIntNodeT(getInt(a) |-| getInt(b), n)
|
||||
of mMulI: result = newIntNodeT(getInt(a) |*| getInt(b), n)
|
||||
of mMinI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
|
||||
else: result = newIntNodeT(getInt(a), n)
|
||||
of mMaxI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
|
||||
else: result = newIntNodeT(getInt(b), n)
|
||||
of mShlI, mShlI64:
|
||||
of mShlI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
|
||||
|
|
@ -327,7 +327,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
|
||||
else: internalError(n.info, "constant folding for shl")
|
||||
of mShrI, mShrI64:
|
||||
of mShrI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
|
||||
|
|
@ -335,14 +335,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||
else: internalError(n.info, "constant folding for shr")
|
||||
of mDivI, mDivI64:
|
||||
of mDivI:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(getInt(a) div y, n)
|
||||
of mModI, mModI64:
|
||||
result = newIntNodeT(`|div|`(getInt(a), y), n)
|
||||
of mModI:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(getInt(a) mod y, n)
|
||||
result = newIntNodeT(`|mod|`(getInt(a), y), n)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
||||
|
|
@ -359,11 +359,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
|
||||
else: result = newFloatNodeT(getFloat(a), n)
|
||||
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
|
||||
of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
|
||||
of mLtI, mLtB, mLtEnum, mLtCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
|
||||
of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
|
||||
of mLeI, mLeB, mLeEnum, mLeCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
|
||||
of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
|
||||
of mEqI, mEqB, mEqEnum, mEqCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
|
||||
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
|
||||
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
|
||||
|
|
@ -375,9 +375,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
|
||||
of mLeU, mLeU64:
|
||||
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
|
||||
of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
|
||||
of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
|
||||
of mBitxorI, mBitxorI64, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
|
||||
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
|
||||
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
|
||||
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
|
||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||
|
|
@ -430,14 +430,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of mCompileOptionArg:
|
||||
result = newIntNodeT(ord(
|
||||
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
|
||||
of mNewString, mNewStringOfCap,
|
||||
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
|
||||
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
|
||||
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
|
||||
mParallel, mPlugin:
|
||||
discard
|
||||
else: internalError(a.info, "evalOp(" & $m & ')')
|
||||
of mEqProc:
|
||||
result = newIntNodeT(ord(
|
||||
exprStructuralEquivalent(a, b, strictSymEquality=true)), n)
|
||||
else: discard
|
||||
|
||||
proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||
result = nil
|
||||
|
|
@ -540,7 +536,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
|
|||
of tyFloat..tyFloat64:
|
||||
case skipTypes(a.typ, abstractRange).kind
|
||||
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
||||
result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
|
||||
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ type
|
|||
GenericCtx = object
|
||||
toMixin: IntSet
|
||||
cursorInBody: bool # only for nimsuggest
|
||||
bracketExpr: PNode
|
||||
|
||||
type
|
||||
TSemGenericFlag = enum
|
||||
|
|
@ -39,9 +40,9 @@ type
|
|||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode
|
||||
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx): PNode =
|
||||
ctx: var GenericCtx): PNode =
|
||||
openScope(c)
|
||||
result = semGenericStmt(c, n, flags, ctx)
|
||||
closeScope(c)
|
||||
|
|
@ -57,7 +58,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
|||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
result = n
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
of skProc, skMethod, skIterators, skConverter, skModule:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
|
|
@ -73,7 +74,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
|||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
of skGenericParam:
|
||||
if s.typ != nil and s.typ.kind == tyStatic:
|
||||
if s.typ.n != nil:
|
||||
result = s.typ.n
|
||||
|
|
@ -85,18 +86,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
|||
of skParam:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
of skType:
|
||||
of skType:
|
||||
if (s.typ != nil) and
|
||||
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else:
|
||||
else:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx): PNode =
|
||||
result = n
|
||||
let ident = considerQuotedIdent(n)
|
||||
|
|
@ -118,13 +119,13 @@ proc newDot(n, b: PNode): PNode =
|
|||
result.add(n.sons[0])
|
||||
result.add(b)
|
||||
|
||||
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx; isMacro: var bool): PNode =
|
||||
assert n.kind == nkDotExpr
|
||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||
|
||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
|
||||
|
||||
var s = qualifiedLookUp(c, n, luf)
|
||||
if s != nil:
|
||||
result = semGenericStmtSymbol(c, n, s, ctx)
|
||||
|
|
@ -141,18 +142,20 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
|||
elif s.name.id in ctx.toMixin:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
let sym = semGenericStmtSymbol(c, n, s, ctx)
|
||||
if sym.kind == nkSym:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
let syms = semGenericStmtSymbol(c, n, s, ctx)
|
||||
if syms.kind == nkSym:
|
||||
let choice = symChoice(c, n, s, scForceOpen)
|
||||
choice.kind = nkClosedSymChoice
|
||||
result = newDot(result, choice)
|
||||
else:
|
||||
result = newDot(result, sym)
|
||||
result = newDot(result, syms)
|
||||
|
||||
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
let s = newSymS(skUnknown, getIdentNode(n), c)
|
||||
addPrelimDecl(c, s)
|
||||
styleCheckDef(n.info, s, kind)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
|
||||
result = n
|
||||
#if gCmd == cmdIdeTools: suggestStmt(c, n)
|
||||
|
|
@ -181,16 +184,16 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
|
||||
of nkMixinStmt:
|
||||
result = semMixinStmt(c, n, ctx.toMixin)
|
||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
let fn = n.sons[0]
|
||||
var s = qualifiedLookUp(c, fn, {})
|
||||
if s == nil and withinMixin notin flags and
|
||||
fn.kind in {nkIdent, nkAccQuoted} and
|
||||
fn.kind in {nkIdent, nkAccQuoted} and
|
||||
considerQuotedIdent(fn).id notin ctx.toMixin:
|
||||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||
|
||||
|
||||
var first = 0
|
||||
var mixinContext = false
|
||||
if s != nil:
|
||||
|
|
@ -220,19 +223,23 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
|
||||
# the famous "undeclared identifier: it" bug:
|
||||
mixinContext = true
|
||||
of skUnknown, skParam:
|
||||
of skUnknown, skParam:
|
||||
# Leave it as an identifier.
|
||||
discard
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
of skProc, skMethod, skIterators, skConverter, skModule:
|
||||
result.sons[0] = symChoice(c, fn, s, scOption)
|
||||
# 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 == "^":
|
||||
result.add ctx.bracketExpr
|
||||
first = 1
|
||||
of skGenericParam:
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
of skType:
|
||||
of skType:
|
||||
# bad hack for generics:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
|
|
@ -244,34 +251,68 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||
first = 1
|
||||
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||
for i in countup(first, sonsLen(result) - 1):
|
||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||
of nkIfStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("{}"), n.info)
|
||||
for i in 0 ..< n.len: result.add(n[i])
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("[]"), n.info)
|
||||
for i in 0 ..< n.len: result.add(n[i])
|
||||
withBracketExpr ctx, n.sons[0]:
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
of nkAsgn, nkFastAsgn:
|
||||
checkSonsLen(n, 2)
|
||||
let a = n.sons[0]
|
||||
let b = n.sons[1]
|
||||
|
||||
let k = a.kind
|
||||
case k
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("{}="), n.info)
|
||||
for i in 0 ..< a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("[]="), n.info)
|
||||
for i in 0 ..< a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
withBracketExpr ctx, a.sons[0]:
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
of nkIfStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
||||
of nkWhenStmt:
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
|
||||
of nkWhileStmt:
|
||||
of nkWhileStmt:
|
||||
openScope(c)
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkCaseStmt:
|
||||
of nkCaseStmt:
|
||||
openScope(c)
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1)
|
||||
var L = sonsLen(a)
|
||||
for j in countup(0, L-2):
|
||||
for j in countup(0, L-2):
|
||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
|
||||
a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkForStmt, nkParForStmt:
|
||||
of nkForStmt, nkParForStmt:
|
||||
var L = sonsLen(n)
|
||||
openScope(c)
|
||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||
|
|
@ -279,27 +320,27 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
addTempDecl(c, n.sons[i], skForVar)
|
||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
addTempDecl(c, n.sons[0], skLabel)
|
||||
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkTryStmt:
|
||||
of nkTryStmt:
|
||||
checkMinSonsLen(n, 2)
|
||||
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1)
|
||||
var L = sonsLen(a)
|
||||
for j in countup(0, L-2):
|
||||
for j in countup(0, L-2):
|
||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkVarSection, nkLetSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
|
|
@ -307,79 +348,79 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
||||
of nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addTempDecl(c, getIdentNode(a.sons[0]), skType)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
if a.sons[1].kind != nkEmpty:
|
||||
if a.sons[1].kind != nkEmpty:
|
||||
openScope(c)
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||
closeScope(c)
|
||||
else:
|
||||
else:
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
|
||||
of nkEnumTy:
|
||||
of nkEnumTy:
|
||||
if n.sonsLen > 0:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a: PNode
|
||||
case n.sons[i].kind
|
||||
of nkEnumFieldDef: a = n.sons[i].sons[0]
|
||||
of nkIdent: a = n.sons[i]
|
||||
else: illFormedAst(n)
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a), c))
|
||||
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||
discard
|
||||
of nkFormalParams:
|
||||
checkMinSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var L = sonsLen(a)
|
||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in countup(0, L-3):
|
||||
for j in countup(0, L-3):
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambdaKinds:
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambdaKinds:
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
if n.sons[namePos].kind != nkEmpty:
|
||||
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
||||
openScope(c)
|
||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||
flags, ctx)
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||
|
|
@ -394,7 +435,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
checkMinSonsLen(n, 2)
|
||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||
|
|
|
|||
|
|
@ -10,14 +10,10 @@
|
|||
# This module implements the instantiation of generic procs.
|
||||
# included from sem.nim
|
||||
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiation) =
|
||||
if n.kind != nkGenericParams:
|
||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
newSeq(entry.concreteTypes, n.len)
|
||||
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
||||
internalAssert n.kind == nkGenericParams
|
||||
for i, a in n.pairs:
|
||||
if a.kind != nkSym:
|
||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
internalAssert a.kind == nkSym
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||
continue
|
||||
|
|
@ -42,8 +38,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
|||
#t = ReplaceTypeVarsT(cl, t)
|
||||
s.typ = t
|
||||
if t.kind == tyStatic: s.ast = t.n
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = t
|
||||
yield s
|
||||
|
||||
proc sameInstantiation(a, b: TInstantiation): bool =
|
||||
if a.concreteTypes.len == b.concreteTypes.len:
|
||||
|
|
@ -52,10 +47,11 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
|||
flags = {ExactTypeDescValues}): return
|
||||
result = true
|
||||
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
|
||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||
id: CompilesId): PSym =
|
||||
if genericSym.procInstCache != nil:
|
||||
for inst in genericSym.procInstCache:
|
||||
if sameInstantiation(entry, inst[]):
|
||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||
return inst.sym
|
||||
|
||||
proc removeDefaultParamValues(n: PNode) =
|
||||
|
|
@ -169,7 +165,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
|||
addDecl(c, prc)
|
||||
|
||||
pushInfoContext(info)
|
||||
var cl = initTypeVars(c, pt, info)
|
||||
var cl = initTypeVars(c, pt, info, nil)
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
|
|
@ -217,7 +213,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
||||
## parameters to their concrete types within the generic instance.
|
||||
# no need to instantiate generic templates/macros:
|
||||
if fn.kind in {skTemplate, skMacro}: return fn
|
||||
internalAssert fn.kind notin {skMacro, skTemplate}
|
||||
# generates an instantiated proc
|
||||
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
||||
inc(c.instCounter)
|
||||
|
|
@ -226,30 +222,49 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
# NOTE: for access of private fields within generics from a different module
|
||||
# we set the friend module:
|
||||
c.friendModules.add(getModule(fn))
|
||||
#let oldScope = c.currentScope
|
||||
#c.currentScope = fn.scope
|
||||
let oldInTypeClass = c.inTypeClass
|
||||
c.inTypeClass = 0
|
||||
let oldScope = c.currentScope
|
||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||
result = copySym(fn, false)
|
||||
incl(result.flags, sfFromGeneric)
|
||||
result.owner = fn
|
||||
result.ast = n
|
||||
pushOwner(result)
|
||||
|
||||
openScope(c)
|
||||
internalAssert n.sons[genericParamsPos].kind != nkEmpty
|
||||
let gp = n.sons[genericParamsPos]
|
||||
internalAssert gp.kind != nkEmpty
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
pushInfoContext(info)
|
||||
var entry = TInstantiation.new
|
||||
entry.sym = result
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
||||
# we need to compare both the generic types and the concrete types:
|
||||
# generic[void](), generic[int]()
|
||||
# see ttypeor.nim test.
|
||||
var i = 0
|
||||
newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
|
||||
for s in instantiateGenericParamList(c, gp, pt):
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = s.typ
|
||||
inc i
|
||||
pushProcCon(c, result)
|
||||
instantiateProcType(c, pt, result, info)
|
||||
for j in 1 .. result.typ.len-1:
|
||||
entry.concreteTypes[i] = result.typ.sons[j]
|
||||
inc i
|
||||
if tfTriggersCompileTime in result.typ.flags:
|
||||
incl(result.flags, sfCompileTime)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
var oldPrc = genericCacheGet(fn, entry[])
|
||||
var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
|
||||
if oldPrc == nil:
|
||||
# we MUST not add potentially wrong instantiations to the caching mechanism.
|
||||
# This means recursive instantiations behave differently when in
|
||||
# a ``compiles`` context but this is the lesser evil. See
|
||||
# bug #1055 (tevilcompiles).
|
||||
if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry)
|
||||
#if c.compilesContextId == 0:
|
||||
entry.compilesId = c.compilesContextId
|
||||
fn.procInstCache.safeAdd(entry)
|
||||
c.generics.add(makeInstPair(fn, entry))
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
|
|
@ -264,7 +279,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
popInfoContext()
|
||||
closeScope(c) # close scope for parameters
|
||||
popOwner()
|
||||
#c.currentScope = oldScope
|
||||
c.currentScope = oldScope
|
||||
discard c.friendModules.pop()
|
||||
dec(c.instCounter)
|
||||
c.inTypeClass = oldInTypeClass
|
||||
if result.kind == skMethod: finishMethod(c, result)
|
||||
|
|
|
|||
|
|
@ -38,14 +38,16 @@ proc annotateType*(n: PNode, t: PType) =
|
|||
# Note: x can be unequal to t and we need to be careful to use 't'
|
||||
# to not to skip tyGenericInst
|
||||
case n.kind
|
||||
of nkObjConstr:
|
||||
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
|
||||
else:
|
||||
internalAssert(n.sons[i].kind == nkExprColonExpr)
|
||||
annotateType(n.sons[i].sons[1], field.typ)
|
||||
of nkPar:
|
||||
if x.kind == tyObject:
|
||||
n.typ = t
|
||||
for i in 0 .. <n.len:
|
||||
let field = x.n.ithField(i)
|
||||
if field.isNil: globalError n.info, "invalid field at index " & $i
|
||||
else: annotateType(n.sons[i], field.typ)
|
||||
elif x.kind == tyTuple:
|
||||
if x.kind == tyTuple:
|
||||
n.typ = t
|
||||
for i in 0 .. <n.len:
|
||||
if i >= x.len: globalError n.info, "invalid field at index " & $i
|
||||
|
|
@ -53,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) =
|
|||
elif x.kind == tyProc and x.callConv == ccClosure:
|
||||
n.typ = t
|
||||
else:
|
||||
globalError(n.info, "() must have an object or tuple type")
|
||||
globalError(n.info, "() must have a tuple type")
|
||||
of nkBracket:
|
||||
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}:
|
||||
n.typ = t
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@
|
|||
# This include file implements the semantic checking for magics.
|
||||
# included from sem.nim
|
||||
|
||||
proc semAddr(c: PContext; n: PNode): PNode =
|
||||
proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
|
||||
result = newNodeI(nkAddr, n.info)
|
||||
let x = semExprWithType(c, n)
|
||||
if isAssignable(c, x) notin {arLValue, arLocalLValue}:
|
||||
if x.kind == nkSym:
|
||||
x.sym.flags.incl(sfAddrTaken)
|
||||
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
|
||||
localError(n.info, errExprHasNoAddress)
|
||||
result.add x
|
||||
result.typ = makePtrType(c, x.typ)
|
||||
|
|
@ -24,6 +26,41 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
|
|||
result.add typExpr
|
||||
result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
|
||||
|
||||
type
|
||||
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
|
||||
|
||||
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
|
||||
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc skipAddr(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n.sons[0] else: n)
|
||||
|
||||
proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
result = newNodeI(nkBracketExpr, n.info)
|
||||
for i in 1..<n.len: result.add(n[i])
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
result = semSubscript(c, result, flags)
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
if result.isNil:
|
||||
localError(n.info, "could not resolve: " & $n)
|
||||
result = n
|
||||
|
||||
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
|
||||
let b = newNodeI(nkBracketExpr, n.info)
|
||||
b.add(n[1].skipAddr)
|
||||
for i in 2..n.len-2: b.add(n[i])
|
||||
result = newNodeI(nkAsgn, n.info, 2)
|
||||
result.sons[0] = b
|
||||
result.sons[1] = n.lastSon
|
||||
result = semAsgn(c, result, noOverloadedSubscript)
|
||||
|
||||
proc semAsgnOpr(c: PContext; n: PNode): PNode =
|
||||
result = newNodeI(nkAsgn, n.info, 2)
|
||||
result.sons[0] = n[1]
|
||||
result.sons[1] = n[2]
|
||||
result = semAsgn(c, result, noOverloadedAsgn)
|
||||
|
||||
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var r = isPartOf(n[1], n[2])
|
||||
result = newIntNodeT(ord(r), n)
|
||||
|
|
@ -119,10 +156,13 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
|||
case n[0].sym.magic
|
||||
of mAddr:
|
||||
checkSonsLen(n, 2)
|
||||
result = semAddr(c, n.sons[1])
|
||||
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
|
||||
of mTypeOf:
|
||||
checkSonsLen(n, 2)
|
||||
result = semTypeOf(c, n.sons[1])
|
||||
of mArrGet: result = semArrGet(c, n, flags)
|
||||
of mArrPut: result = semArrPut(c, n, flags)
|
||||
of mAsgn: result = semAsgnOpr(c, n)
|
||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||
of mTypeTrait: result = semTypeTraits(c, n)
|
||||
of mAstToStr:
|
||||
|
|
@ -143,25 +183,28 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
|||
if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
|
||||
localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
|
||||
of mRoof:
|
||||
# error correction:
|
||||
result = n.sons[1]
|
||||
if c.p.bracketExpr.isNil:
|
||||
let bracketExpr = if n.len == 3: n.sons[2] else: c.p.bracketExpr
|
||||
if bracketExpr.isNil:
|
||||
localError(n.info, "no surrounding array access context for '^'")
|
||||
elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
|
||||
result = n.sons[1]
|
||||
elif bracketExpr.checkForSideEffects != seNoSideEffect:
|
||||
localError(n.info, "invalid context for '^' as '$#' has side effects" %
|
||||
renderTree(c.p.bracketExpr))
|
||||
elif c.p.bracketExpr.typ.isStrangeArray:
|
||||
renderTree(bracketExpr))
|
||||
result = n.sons[1]
|
||||
elif bracketExpr.typ.isStrangeArray:
|
||||
localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
|
||||
renderTree(c.p.bracketExpr))
|
||||
renderTree(bracketExpr))
|
||||
result = n.sons[1]
|
||||
else:
|
||||
# ^x is rewritten to: len(a)-x
|
||||
let lenExpr = newNodeI(nkCall, n.info)
|
||||
lenExpr.add newIdentNode(getIdent"len", n.info)
|
||||
lenExpr.add c.p.bracketExpr
|
||||
lenExpr.add bracketExpr
|
||||
let lenExprB = semExprWithType(c, lenExpr)
|
||||
if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
|
||||
localError(n.info, "'$#' has to be of an ordinal type for '^'" %
|
||||
renderTree(lenExpr))
|
||||
result = n.sons[1]
|
||||
else:
|
||||
result = newNodeIT(nkCall, n.info, getSysType(tyInt))
|
||||
result.add newSymNode(createMagic("-", mSubI), n.info)
|
||||
|
|
|
|||
|
|
@ -128,10 +128,10 @@ template `?`(x): expr = x.renderTree
|
|||
proc checkLe(c: AnalysisCtx; a, b: PNode) =
|
||||
case proveLe(c.guards, a, b)
|
||||
of impUnknown:
|
||||
localError(a.info, "cannot prove: " & ?a & " <= " & ?b)
|
||||
localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
|
||||
of impYes: discard
|
||||
of impNo:
|
||||
localError(a.info, "can prove: " & ?a & " > " & ?b)
|
||||
localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
|
||||
|
||||
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
|
||||
checkLe(c, arr.lowBound, idx)
|
||||
|
|
@ -156,19 +156,23 @@ proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
|
|||
|
||||
proc overlap(m: TModel; x,y,c,d: PNode) =
|
||||
# X..Y and C..D overlap iff (X <= D and C <= Y)
|
||||
case proveLe(m, x, d)
|
||||
case proveLe(m, c, y)
|
||||
of impUnknown:
|
||||
localError(x.info,
|
||||
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
|
||||
[?x, ?d, ?x, ?y, ?c, ?d])
|
||||
case proveLe(m, x, d)
|
||||
of impNo: discard
|
||||
of impUnknown, impYes:
|
||||
localError(x.info,
|
||||
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
|
||||
[?c, ?y, ?x, ?y, ?c, ?d])
|
||||
of impYes:
|
||||
case proveLe(m, c, y)
|
||||
case proveLe(m, x, d)
|
||||
of impUnknown:
|
||||
localError(x.info,
|
||||
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
|
||||
[?c, ?y, ?x, ?y, ?c, ?d])
|
||||
[?x, ?d, ?x, ?y, ?c, ?d])
|
||||
of impYes:
|
||||
localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" % [?x, ?y, ?c, ?d])
|
||||
localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" %
|
||||
[?c, ?y, ?x, ?y, ?c, ?d])
|
||||
of impNo: discard
|
||||
of impNo: discard
|
||||
|
||||
|
|
@ -278,10 +282,12 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
|
|||
slot.stride = min(slot.stride, incr)
|
||||
analyseSons(c, n)
|
||||
elif op.name.s == "[]" and op.fromSystem:
|
||||
c.addSlice(n, n[1], n[2][1], n[2][2])
|
||||
let slice = n[2].skipStmtList
|
||||
c.addSlice(n, n[1], slice[1], slice[2])
|
||||
analyseSons(c, n)
|
||||
elif op.name.s == "[]=" and op.fromSystem:
|
||||
c.addSlice(n, n[1], n[2][1], n[2][2])
|
||||
let slice = n[2].skipStmtList
|
||||
c.addSlice(n, n[1], slice[1], slice[2])
|
||||
analyseSons(c, n)
|
||||
else:
|
||||
analyseSons(c, n)
|
||||
|
|
@ -363,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
|||
else: internalError(it.info, "slot already has a lower bound")
|
||||
if not isSpawned: analyse(c, value)
|
||||
of nkCaseStmt: analyseCase(c, n)
|
||||
of nkIfStmt, nkIfExpr: analyseIf(c, n)
|
||||
of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
|
||||
of nkWhileStmt:
|
||||
analyse(c, n.sons[0])
|
||||
# 'while true' loop?
|
||||
|
|
@ -395,8 +401,9 @@ proc transformSlices(n: PNode): PNode =
|
|||
result = copyNode(n)
|
||||
result.add opSlice.newSymNode
|
||||
result.add n[1]
|
||||
result.add n[2][1]
|
||||
result.add n[2][2]
|
||||
let slice = n[2].skipStmtList
|
||||
result.add slice[1]
|
||||
result.add slice[2]
|
||||
return result
|
||||
if n.safeLen > 0:
|
||||
result = shallowCopy(n)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
wordrecg, strutils, options, guards
|
||||
wordrecg, strutils, options, guards, writetracking
|
||||
|
||||
# Second semantic checking pass over the AST. Necessary because the old
|
||||
# way had some inherent problems. Performs:
|
||||
|
|
@ -17,7 +17,7 @@ import
|
|||
# * effect+exception tracking
|
||||
# * "usage before definition" checking
|
||||
# * checks for invalid usages of compiletime magics (not implemented)
|
||||
# * checks for invalid usages of PNimNode (not implemented)
|
||||
# * checks for invalid usages of NimNode (not implemented)
|
||||
# * later: will do an escape analysis for closures at least
|
||||
|
||||
# Predefined effects:
|
||||
|
|
@ -29,21 +29,6 @@ import
|
|||
# --> a TR macro can annotate the proc with user defined annotations
|
||||
# --> the effect system can access these
|
||||
|
||||
# Load&Store analysis is performed on *paths*. A path is an access like
|
||||
# obj.x.y[i].z; splitting paths up causes some problems:
|
||||
#
|
||||
# var x = obj.x
|
||||
# var z = x.y[i].z
|
||||
#
|
||||
# Alias analysis is affected by this too! A good solution is *type splitting*:
|
||||
# T becomes T1 and T2 if it's known that T1 and T2 can't alias.
|
||||
#
|
||||
# An aliasing problem and a race condition are effectively the same problem.
|
||||
# Type based alias analysis is nice but not sufficient; especially splitting
|
||||
# an array and filling it in parallel should be supported but is not easily
|
||||
# done: It essentially requires a built-in 'indexSplit' operation and dependent
|
||||
# typing.
|
||||
|
||||
# ------------------------ exception and tag tracking -------------------------
|
||||
|
||||
discard """
|
||||
|
|
@ -207,9 +192,9 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
|
|||
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
|
||||
a.owner, reason.info)
|
||||
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
||||
let u = s.gcUnsafetyReason
|
||||
if u != nil:
|
||||
if u != nil and not cycleCheck.containsOrIncl(u.id):
|
||||
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
|
||||
if u.kind in {skLet, skVar}:
|
||||
message(s.info, msgKind,
|
||||
|
|
@ -218,7 +203,7 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
|||
elif u.kind in routineKinds:
|
||||
# recursive call *always* produces only a warning so the full error
|
||||
# message is printed:
|
||||
listGcUnsafety(u, true)
|
||||
listGcUnsafety(u, true, cycleCheck)
|
||||
message(s.info, msgKind,
|
||||
"'$#' is not GC-safe as it calls '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
|
|
@ -227,6 +212,10 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
|||
message(u.info, msgKind,
|
||||
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
|
||||
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
||||
var cycleCheck = initIntSet()
|
||||
listGcUnsafety(s, onlyWarning, cycleCheck)
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if isLocalVar(a, s):
|
||||
|
|
@ -237,9 +226,10 @@ proc useVar(a: PEffects, n: PNode) =
|
|||
message(n.info, warnUninit, s.name.s)
|
||||
# prevent superfluous warnings about the same variable:
|
||||
a.init.add s.id
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
|
||||
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet}:
|
||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
|
||||
(tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||
#if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(a, s)
|
||||
|
||||
|
|
@ -433,17 +423,41 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
|
|||
result = newNode(nkExprColonExpr, n.info, @[
|
||||
newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
|
||||
|
||||
proc documentWriteEffect(n: PNode; flag: TSymFlag; pragmaName: string): PNode =
|
||||
let s = n.sons[namePos].sym
|
||||
let params = s.typ.n
|
||||
|
||||
var effects = newNodeI(nkBracket, n.info)
|
||||
for i in 1 ..< params.len:
|
||||
if params[i].kind == nkSym and flag in params[i].sym.flags:
|
||||
effects.add params[i]
|
||||
|
||||
if effects.len > 0:
|
||||
result = newNode(nkExprColonExpr, n.info, @[
|
||||
newIdentNode(getIdent(pragmaName), n.info), effects])
|
||||
|
||||
proc documentNewEffect(n: PNode): PNode =
|
||||
let s = n.sons[namePos].sym
|
||||
if tfReturnsNew in s.typ.flags:
|
||||
result = newIdentNode(getIdent("new"), n.info)
|
||||
|
||||
proc documentRaises*(n: PNode) =
|
||||
if n.sons[namePos].kind != nkSym: return
|
||||
let pragmas = n.sons[pragmasPos]
|
||||
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
|
||||
let p2 = documentEffect(n, pragmas, wTags, tagEffects)
|
||||
let p3 = documentWriteEffect(n, sfWrittenTo, "writes")
|
||||
let p4 = documentNewEffect(n)
|
||||
let p5 = documentWriteEffect(n, sfEscapes, "escapes")
|
||||
|
||||
if p1 != nil or p2 != nil:
|
||||
if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil:
|
||||
if pragmas.kind == nkEmpty:
|
||||
n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
|
||||
if p1 != nil: n.sons[pragmasPos].add p1
|
||||
if p2 != nil: n.sons[pragmasPos].add p2
|
||||
if p3 != nil: n.sons[pragmasPos].add p3
|
||||
if p4 != nil: n.sons[pragmasPos].add p4
|
||||
if p5 != nil: n.sons[pragmasPos].add p5
|
||||
|
||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||
|
||||
|
|
@ -721,7 +735,7 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
||||
# inference for (a, b) and thus no nil checking is necessary.
|
||||
of nkCaseStmt: trackCase(tracked, n)
|
||||
of nkIfStmt, nkIfExpr: trackIf(tracked, n)
|
||||
of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
|
||||
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1])
|
||||
of nkWhileStmt:
|
||||
track(tracked, n.sons[0])
|
||||
|
|
@ -748,7 +762,7 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
for i in 1 .. <len(n):
|
||||
let x = n.sons[i]
|
||||
track(tracked, x)
|
||||
if sfDiscriminant in x.sons[0].sym.flags:
|
||||
if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
|
||||
addDiscriminantFact(tracked.guards, x)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
of nkPragmaBlock:
|
||||
|
|
@ -841,6 +855,8 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
|||
newSeq(effects.sons, effectListLen)
|
||||
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[usesEffects] = ast.emptyNode
|
||||
effects.sons[writeEffects] = ast.emptyNode
|
||||
|
||||
t.exc = effects.sons[exceptionEffects]
|
||||
t.tags = effects.sons[tagEffects]
|
||||
|
|
@ -895,6 +911,7 @@ proc trackProc*(s: PSym, body: PNode) =
|
|||
message(s.info, warnLockLevel,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
when useWriteTracking: trackWrites(s, body)
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
||||
|
|
|
|||
|
|
@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
|
|||
else:
|
||||
result.add identDefs
|
||||
|
||||
proc addDefer(c: PContext; result: var PNode; s: PSym) =
|
||||
let deferDestructorCall = createDestructorCall(c, s)
|
||||
if deferDestructorCall != nil:
|
||||
if result.kind != nkStmtList:
|
||||
let oldResult = result
|
||||
result = newNodeI(nkStmtList, result.info)
|
||||
result.add oldResult
|
||||
result.add deferDestructorCall
|
||||
|
||||
proc isDiscardUnderscore(v: PSym): bool =
|
||||
if v.name.s == "_":
|
||||
v.flags.incl(sfGenSym)
|
||||
|
|
@ -469,6 +478,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
if def.kind == nkPar: v.ast = def[j]
|
||||
v.typ = tup.sons[j]
|
||||
b.sons[j] = newSymNode(v)
|
||||
addDefer(c, result, v)
|
||||
checkNilable(v)
|
||||
if sfCompileTime in v.flags: hasCompileTime = true
|
||||
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
||||
|
|
@ -744,13 +754,62 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
|||
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||
checkForMetaFields(s.typ.n)
|
||||
|
||||
proc semAllTypeSections(c: PContext; n: PNode): PNode =
|
||||
proc gatherStmts(c: PContext; n: PNode; result: PNode) {.nimcall.} =
|
||||
case n.kind
|
||||
of nkIncludeStmt:
|
||||
for i in 0..<n.len:
|
||||
var f = checkModuleName(n.sons[i])
|
||||
if f != InvalidFileIDX:
|
||||
if containsOrIncl(c.includedFiles, f):
|
||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||
else:
|
||||
let code = gIncludeFile(c.module, f)
|
||||
gatherStmts c, code, result
|
||||
excl(c.includedFiles, f)
|
||||
of nkStmtList:
|
||||
for i in 0 ..< n.len:
|
||||
gatherStmts(c, n.sons[i], result)
|
||||
of nkTypeSection:
|
||||
incl n.flags, nfSem
|
||||
typeSectionLeftSidePass(c, n)
|
||||
result.add n
|
||||
else:
|
||||
result.add n
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
gatherStmts(c, n, result)
|
||||
|
||||
template rec(name) =
|
||||
for i in 0 ..< result.len:
|
||||
if result[i].kind == nkTypeSection:
|
||||
name(c, result[i])
|
||||
|
||||
rec typeSectionRightSidePass
|
||||
rec typeSectionFinalPass
|
||||
when false:
|
||||
# too beautiful to delete:
|
||||
template rec(name; setbit=false) =
|
||||
proc `name rec`(c: PContext; n: PNode) {.nimcall.} =
|
||||
if n.kind == nkTypeSection:
|
||||
when setbit: incl n.flags, nfSem
|
||||
name(c, n)
|
||||
elif n.kind == nkStmtList:
|
||||
for i in 0 ..< n.len:
|
||||
`name rec`(c, n.sons[i])
|
||||
`name rec`(c, n)
|
||||
rec typeSectionLeftSidePass, true
|
||||
rec typeSectionRightSidePass
|
||||
rec typeSectionFinalPass
|
||||
|
||||
proc semTypeSection(c: PContext, n: PNode): PNode =
|
||||
## Processes a type section. This must be done in separate passes, in order
|
||||
## to allow the type definitions in the section to reference each other
|
||||
## without regard for the order of their definitions.
|
||||
typeSectionLeftSidePass(c, n)
|
||||
typeSectionRightSidePass(c, n)
|
||||
typeSectionFinalPass(c, n)
|
||||
if sfNoForward notin c.module.flags or nfSem notin n.flags:
|
||||
typeSectionLeftSidePass(c, n)
|
||||
typeSectionRightSidePass(c, n)
|
||||
typeSectionFinalPass(c, n)
|
||||
result = n
|
||||
|
||||
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
|
||||
|
|
@ -898,27 +957,35 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
var n = n
|
||||
|
||||
n = replaceTypesInBody(c, pt, n)
|
||||
let original = n.sons[namePos].sym
|
||||
let s = copySym(original, false)
|
||||
incl(s.flags, sfFromGeneric)
|
||||
|
||||
n = replaceTypesInBody(c, pt, n, original)
|
||||
result = n
|
||||
|
||||
s.ast = result
|
||||
n.sons[namePos].sym = s
|
||||
n.sons[genericParamsPos] = emptyNode
|
||||
n.sons[paramsPos] = n.typ.n
|
||||
|
||||
let params = n.typ.n
|
||||
n.sons[paramsPos] = params
|
||||
s.typ = n.typ
|
||||
for i in 1..<params.len:
|
||||
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
|
||||
tyFromExpr, tyFieldAccessor}+tyTypeClasses:
|
||||
localError(params[i].info, "cannot infer type of parameter: " &
|
||||
params[i].sym.name.s)
|
||||
openScope(c)
|
||||
var s = n.sons[namePos].sym
|
||||
pushOwner(s)
|
||||
addParams(c, n.typ.n, skProc)
|
||||
addParams(c, params, skProc)
|
||||
pushProcCon(c, s)
|
||||
addResult(c, n.typ.sons[0], n.info, skProc)
|
||||
addResultNode(c, n)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||
popProcCon(c)
|
||||
popOwner()
|
||||
closeScope(c)
|
||||
|
||||
s.ast = result
|
||||
|
||||
# alternative variant (not quite working):
|
||||
# var prc = arg[0].sym
|
||||
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
|
||||
|
|
@ -974,6 +1041,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
|||
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
||||
incl(s.flags, sfUsed)
|
||||
of "=":
|
||||
if s.magic == mAsgn: return
|
||||
incl(s.flags, sfUsed)
|
||||
let t = s.typ
|
||||
if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
|
||||
|
|
@ -1033,12 +1101,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
n.sons[namePos] = newSymNode(s)
|
||||
s.ast = n
|
||||
#s.scope = c.currentScope
|
||||
|
||||
if sfNoForward in c.module.flags and
|
||||
sfSystemModule notin c.module.flags:
|
||||
addInterfaceOverloadableSymAt(c, c.currentScope, s)
|
||||
s.flags.incl sfForward
|
||||
return
|
||||
when false:
|
||||
# disable for now
|
||||
if sfNoForward in c.module.flags and
|
||||
sfSystemModule notin c.module.flags:
|
||||
addInterfaceOverloadableSymAt(c, c.currentScope, s)
|
||||
s.flags.incl sfForward
|
||||
return
|
||||
else:
|
||||
s = n[namePos].sym
|
||||
s.owner = getCurrOwner()
|
||||
|
|
@ -1071,6 +1140,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
# semParamList(c, n.sons[ParamsPos], nil, s)
|
||||
else:
|
||||
s.typ = newProcType(c, n.info)
|
||||
if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||
if s.kind in skIterators:
|
||||
|
|
@ -1160,6 +1230,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
if n.sons[patternPos].kind != nkEmpty:
|
||||
c.patterns.add(s)
|
||||
if isAnon: result.typ = s.typ
|
||||
if isTopLevel(c) and s.kind != skClosureIterator and
|
||||
s.typ.callConv == ccClosure:
|
||||
message(s.info, warnDeprecated, "top level '.closure' calling convention")
|
||||
|
||||
proc determineType(c: PContext, s: PSym) =
|
||||
if s.typ != nil: return
|
||||
|
|
@ -1268,6 +1341,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
|||
of wLocks:
|
||||
result = n
|
||||
result.typ = n.sons[1].typ
|
||||
of wNoRewrite:
|
||||
incl(result.flags, nfNoRewrite)
|
||||
else: discard
|
||||
|
||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||
|
|
@ -1319,7 +1394,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
for i in countup(0, length - 1):
|
||||
let k = n.sons[i].kind
|
||||
case k
|
||||
of nkFinally, nkExceptBranch, nkDefer:
|
||||
of nkFinally, nkExceptBranch:
|
||||
# stand-alone finally and except blocks are
|
||||
# transformed into regular try blocks:
|
||||
#
|
||||
|
|
@ -1360,7 +1435,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
localError(result.info, "type class predicate failed")
|
||||
of tyUnknown: continue
|
||||
else: discard
|
||||
if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
|
||||
if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]):
|
||||
voidContext = true
|
||||
n.typ = enforceVoidContext
|
||||
if i == last and (length == 1 or efWantValue in flags):
|
||||
|
|
@ -1372,21 +1447,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
case n.sons[i].kind
|
||||
of nkVarSection, nkLetSection:
|
||||
let (outer, inner) = insertDestructors(c, n.sons[i])
|
||||
if outer != nil:
|
||||
n.sons[i] = outer
|
||||
var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
|
||||
inner.addSon(semStmtList(c, rest, flags))
|
||||
n.sons.setLen(i+1)
|
||||
return
|
||||
of LastBlockStmts:
|
||||
for j in countup(i + 1, length - 1):
|
||||
case n.sons[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||
else: discard
|
||||
if result.len == 1:
|
||||
if result.len == 1 and result.sons[0].kind != nkDefer:
|
||||
result = result.sons[0]
|
||||
when defined(nimfix):
|
||||
if result.kind == nkCommentStmt and not result.comment.isNil and
|
||||
|
|
|
|||
|
|
@ -110,6 +110,13 @@ type
|
|||
toBind, toMixin, toInject: IntSet
|
||||
owner: PSym
|
||||
cursorInBody: bool # only for nimsuggest
|
||||
bracketExpr: PNode
|
||||
|
||||
template withBracketExpr(ctx, x, body: untyped) =
|
||||
let old = ctx.bracketExpr
|
||||
ctx.bracketExpr = x
|
||||
body
|
||||
ctx.bracketExpr = old
|
||||
|
||||
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
|
||||
case n.kind
|
||||
|
|
@ -184,10 +191,25 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
|||
else:
|
||||
let ident = getIdentNode(c, n)
|
||||
if not isTemplParam(c, ident):
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(n.info, local)
|
||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||
# fix #2670, consider:
|
||||
#
|
||||
# when b:
|
||||
# var a = "hi"
|
||||
# else:
|
||||
# var a = 5
|
||||
# echo a
|
||||
#
|
||||
# We need to ensure that both 'a' produce the same gensym'ed symbol.
|
||||
# So we need only check the *current* scope.
|
||||
let s = localSearchInScope(c.c, considerQuotedIdent ident)
|
||||
if s != nil and s.owner == c.owner and sfGenSym in s.flags:
|
||||
styleCheckUse(n.info, s)
|
||||
replaceIdentBySym(n, newSymNode(s, n.info))
|
||||
else:
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(n.info, local)
|
||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||
else:
|
||||
replaceIdentBySym(n, ident)
|
||||
|
||||
|
|
@ -260,6 +282,53 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
|
|||
addLocalDecl(c, a.sons[j], symKind)
|
||||
|
||||
proc semPattern(c: PContext, n: PNode): PNode
|
||||
|
||||
proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
for i in 0.. < n.len:
|
||||
result.sons[i] = semTemplBody(c, n.sons[i])
|
||||
|
||||
proc wrapInBind(c: var TemplCtx; n: PNode; opr: string): PNode =
|
||||
let ident = getIdent(opr)
|
||||
if ident.id in c.toInject: return n
|
||||
|
||||
let s = searchInScopes(c.c, ident)
|
||||
if s != nil:
|
||||
var callee: PNode
|
||||
if contains(c.toBind, s.id):
|
||||
callee = symChoice(c.c, n, s, scClosed)
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
callee = symChoice(c.c, n, s, scForceOpen)
|
||||
elif s.owner == c.owner and sfGenSym in s.flags:
|
||||
# template tmp[T](x: var seq[T]) =
|
||||
# var yz: T
|
||||
incl(s.flags, sfUsed)
|
||||
callee = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
callee = semTemplSymbol(c.c, n, s)
|
||||
|
||||
let call = newNodeI(nkCall, n.info)
|
||||
call.add(callee)
|
||||
for i in 0 .. n.len-1: call.add(n[i])
|
||||
result = newNodeI(nkBind, n.info, 2)
|
||||
result.sons[0] = n
|
||||
result.sons[1] = call
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc oprIsRoof(n: PNode): bool =
|
||||
const roof = "^"
|
||||
case n.kind
|
||||
of nkIdent: result = n.ident.s == roof
|
||||
of nkSym: result = n.sym.name.s == roof
|
||||
of nkAccQuoted:
|
||||
if n.len == 1:
|
||||
result = oprIsRoof(n.sons[0])
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = oprIsRoof(n.sons[0])
|
||||
else: discard
|
||||
|
||||
proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
|
||||
|
|
@ -402,27 +471,65 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
|||
result.sons[1] = semTemplBody(c, n.sons[1])
|
||||
of nkPragma:
|
||||
result = onlyReplaceParams(c, n)
|
||||
else:
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("[]"), n.info)
|
||||
for i in 0 ..< n.len: result.add(n[i])
|
||||
let n0 = semTemplBody(c, n.sons[0])
|
||||
withBracketExpr c, n0:
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("{}"), n.info)
|
||||
for i in 0 ..< n.len: result.add(n[i])
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkAsgn, nkFastAsgn:
|
||||
checkSonsLen(n, 2)
|
||||
let a = n.sons[0]
|
||||
let b = n.sons[1]
|
||||
|
||||
let k = a.kind
|
||||
case k
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("[]="), n.info)
|
||||
for i in 0 ..< a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
let a0 = semTemplBody(c, a.sons[0])
|
||||
withBracketExpr c, a0:
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent("{}="), n.info)
|
||||
for i in 0 ..< a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
result = semTemplBodySons(c, result)
|
||||
else:
|
||||
result = semTemplBodySons(c, n)
|
||||
of nkCallKinds-{nkPostfix}:
|
||||
result = semTemplBodySons(c, n)
|
||||
if c.bracketExpr != nil and n.len == 2 and oprIsRoof(n.sons[0]):
|
||||
result.add c.bracketExpr
|
||||
of nkDotExpr, nkAccQuoted:
|
||||
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||
# so we use the generic code for nkDotExpr too
|
||||
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
if s != nil:
|
||||
# do not symchoice a quoted template parameter (bug #2390):
|
||||
if s.owner == c.owner and s.kind == skParam and
|
||||
n.kind == nkAccQuoted and n.len == 1:
|
||||
incl(s.flags, sfUsed)
|
||||
styleCheckUse(n.info, s)
|
||||
return newSymNode(s, n.info)
|
||||
elif contains(c.toBind, s.id):
|
||||
return symChoice(c.c, n, s, scClosed)
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
return symChoice(c.c, n, s, scForceOpen)
|
||||
else:
|
||||
return symChoice(c.c, n, s, scOpen)
|
||||
result = n
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semTemplBody(c, n.sons[i])
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
if s != nil:
|
||||
# do not symchoice a quoted template parameter (bug #2390):
|
||||
if s.owner == c.owner and s.kind == skParam and
|
||||
n.kind == nkAccQuoted and n.len == 1:
|
||||
incl(s.flags, sfUsed)
|
||||
styleCheckUse(n.info, s)
|
||||
return newSymNode(s, n.info)
|
||||
elif contains(c.toBind, s.id):
|
||||
return symChoice(c.c, n, s, scClosed)
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
return symChoice(c.c, n, s, scForceOpen)
|
||||
else:
|
||||
return symChoice(c.c, n, s, scOpen)
|
||||
result = semTemplBodySons(c, n)
|
||||
else:
|
||||
result = semTemplBodySons(c, n)
|
||||
|
||||
proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
|
|
@ -452,30 +559,9 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
|
|||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semTemplBodyDirty(c, n.sons[i])
|
||||
|
||||
proc transformToExpr(n: PNode): PNode =
|
||||
var realStmt: int
|
||||
result = n
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
realStmt = - 1
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkCommentStmt, nkEmpty, nkNilLit:
|
||||
discard
|
||||
else:
|
||||
if realStmt == - 1: realStmt = i
|
||||
else: realStmt = - 2
|
||||
if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
|
||||
else: n.kind = nkStmtListExpr
|
||||
of nkBlockStmt:
|
||||
n.kind = nkBlockExpr
|
||||
#nkIfStmt: n.kind = nkIfExpr // this is not correct!
|
||||
else:
|
||||
discard
|
||||
|
||||
proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
var s: PSym
|
||||
if c.p.owner.kind == skModule:
|
||||
if isTopLevel(c):
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
|
||||
incl(s.flags, sfGlobal)
|
||||
else:
|
||||
|
|
@ -530,9 +616,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
|||
n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
|
||||
else:
|
||||
n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos])
|
||||
if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
|
||||
n.sons[bodyPos] = transformToExpr(n.sons[bodyPos])
|
||||
# only parameters are resolved, no type checking is performed
|
||||
# only parameters are resolved, no type checking is performed
|
||||
semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
|
||||
closeScope(c)
|
||||
popOwner()
|
||||
|
|
@ -585,6 +669,11 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
|||
localError(n.info, errInvalidExpression)
|
||||
result = n
|
||||
|
||||
proc stupidStmtListExpr(n: PNode): bool =
|
||||
for i in 0 .. n.len-2:
|
||||
if n[i].kind notin {nkEmpty, nkCommentStmt}: return false
|
||||
result = true
|
||||
|
||||
result = n
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
|
|
@ -610,6 +699,12 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
|||
localError(n.info, errInvalidExpression)
|
||||
else:
|
||||
localError(n.info, errInvalidExpression)
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
if stupidStmtListExpr(n):
|
||||
result = semPatternBody(c, n.lastSon)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semPatternBody(c, n.sons[i])
|
||||
of nkCallKinds:
|
||||
let s = qualifiedLookUp(c.c, n.sons[0], {})
|
||||
if s != nil:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ proc newConstraint(c: PContext, k: TTypeKind): PType =
|
|||
|
||||
proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyEnum)
|
||||
elif n.sonsLen == 1:
|
||||
# don't create an empty tyEnum; fixes #3052
|
||||
return errorType(c)
|
||||
var
|
||||
counter, x: BiggestInt
|
||||
e: PSym
|
||||
|
|
@ -130,6 +133,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
|||
let isCall = ord(n.kind in nkCallKinds)
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1)
|
||||
var base = semTypeNode(c, n.lastSon, nil)
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
# check every except the last is an object:
|
||||
for i in isCall .. n.len-2:
|
||||
|
|
@ -137,7 +141,6 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
|||
if region.skipTypes({tyGenericInst}).kind notin {tyError, tyObject}:
|
||||
message n[i].info, errGenerated, "region needs to be an object type"
|
||||
addSonSkipIntLit(result, region)
|
||||
var base = semTypeNode(c, n.lastSon, nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
|
@ -251,19 +254,21 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
|||
|
||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
var base: PType
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
if sonsLen(n) == 3:
|
||||
# 3 = length(array indx base)
|
||||
var indx = semArrayIndex(c, n[1])
|
||||
addSonSkipIntLit(result, indx)
|
||||
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
||||
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||
if not isOrdinalType(indx):
|
||||
let indx = semArrayIndex(c, n[1])
|
||||
var indxB = indx
|
||||
if indxB.kind == tyGenericInst: indxB = lastSon(indxB)
|
||||
if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||
if not isOrdinalType(indxB):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(indx):
|
||||
elif enumHasHoles(indxB):
|
||||
localError(n.sons[1].info, errEnumXHasHoles,
|
||||
typeToString(indx.skipTypes({tyRange})))
|
||||
typeToString(indxB.skipTypes({tyRange})))
|
||||
base = semTypeNode(c, n.sons[2], nil)
|
||||
# ensure we only construct a tyArray when there was no error (bug #3048):
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
addSonSkipIntLit(result, indx)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
localError(n.info, errArrayExpectsTwoTypeParams)
|
||||
|
|
@ -503,8 +508,9 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
|||
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
|
||||
if not isOrdinalType(typ):
|
||||
localError(n.info, errSelectorMustBeOrdinal)
|
||||
elif firstOrd(typ) < 0:
|
||||
localError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s)
|
||||
elif firstOrd(typ) != 0:
|
||||
localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s &
|
||||
") must be 0 for discriminant")
|
||||
elif lengthOrd(typ) > 0x00007FFF:
|
||||
localError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
|
||||
var chckCovered = true
|
||||
|
|
@ -629,7 +635,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
|
|||
result = t
|
||||
if result.kind == tyGenericInvocation:
|
||||
result = result.sons[0]
|
||||
while result.kind in {tyGenericInst, tyGenericBody}:
|
||||
while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr}:
|
||||
result = lastSon(result)
|
||||
|
||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
|
|
@ -651,7 +657,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
if base.isNil:
|
||||
localError(n.info, errIllegalRecursionInTypeX, "object")
|
||||
else:
|
||||
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||
var concreteBase = skipGenericInvocation(base)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
else:
|
||||
|
|
@ -712,12 +718,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
if paramType == nil: return # (e.g. proc return type)
|
||||
|
||||
proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
|
||||
let finalTypId = if typId != nil: typId
|
||||
else: getIdent(paramName & ":type")
|
||||
if genericParams == nil:
|
||||
# This happens with anonymous proc types appearing in signatures
|
||||
# XXX: we need to lift these earlier
|
||||
return
|
||||
let finalTypId = if typId != nil: typId
|
||||
else: getIdent(paramName & ":type")
|
||||
# is this a bindOnce type class already present in the param list?
|
||||
for i in countup(0, genericParams.len - 1):
|
||||
if genericParams.sons[i].sym.name.id == finalTypId.id:
|
||||
|
|
@ -751,7 +757,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
|
||||
case paramType.kind:
|
||||
of tyAnything:
|
||||
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||
result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
|
||||
|
||||
of tyStatic:
|
||||
# proc(a: expr{string}, b: expr{nkLambda})
|
||||
|
|
@ -862,6 +868,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
of tyExpr:
|
||||
if procKind notin {skMacro, skTemplate}:
|
||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
||||
#result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(info, paramType.sym)
|
||||
|
|
@ -964,18 +971,26 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
elif kind == skIterator:
|
||||
# XXX This is special magic we should likely get rid of
|
||||
r = newTypeS(tyExpr, c)
|
||||
message(n.info, warnDeprecated, "implicit return type for 'iterator'")
|
||||
|
||||
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:
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
if r.kind != tyExpr:
|
||||
if r.kind == tyAnything:
|
||||
# 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
|
||||
# compiler is hardly aware of 'auto':
|
||||
r = newTypeS(tyExpr, c)
|
||||
elif r.kind != tyExpr:
|
||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
||||
n.sons[0].info)
|
||||
if lifted != nil: r = lifted
|
||||
r.flags.incl tfRetType
|
||||
if lifted != nil:
|
||||
r = lifted
|
||||
#if r.kind != tyGenericParam:
|
||||
#echo "came here for ", typeToString(r)
|
||||
r.flags.incl tfRetType
|
||||
r = skipIntLit(r)
|
||||
if kind == skIterator:
|
||||
# see tchainediterators
|
||||
|
|
@ -1049,6 +1064,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
|||
return newOrPrevType(tyError, prev, c)
|
||||
else:
|
||||
var m = newCandidate(c, t)
|
||||
m.isNoCall = true
|
||||
matches(c, n, copyTree(n), m)
|
||||
|
||||
if m.state != csMatch and not m.typedescMatched:
|
||||
|
|
@ -1085,6 +1101,7 @@ proc semTypeExpr(c: PContext, n: PNode): PType =
|
|||
result = n.typ.base
|
||||
else:
|
||||
localError(n.info, errTypeExpected, n.renderTree)
|
||||
result = errorType(c)
|
||||
|
||||
proc freshType(res, prev: PType): PType {.inline.} =
|
||||
if prev.isNil:
|
||||
|
|
@ -1140,7 +1157,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
else:
|
||||
result = semAnonTuple(c, n, prev)
|
||||
of nkCallKinds:
|
||||
if isRange(n):
|
||||
let x = n[0]
|
||||
let ident = case x.kind
|
||||
of nkIdent: x.ident
|
||||
of nkSym: x.sym.name
|
||||
of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name
|
||||
else: nil
|
||||
if ident != nil and ident.s == "[]":
|
||||
let b = newNodeI(nkBracketExpr, n.info)
|
||||
for i in 1..<n.len: b.add(n[i])
|
||||
result = semTypeNode(c, b, prev)
|
||||
elif ident != nil and ident.id == ord(wDotDot):
|
||||
result = semRangeAux(c, n, prev)
|
||||
elif n[0].kind notin nkIdentKinds:
|
||||
result = semTypeExpr(c, n)
|
||||
|
|
@ -1326,12 +1353,23 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
rawAddSon(m.typ, newTypeS(tyEmpty, c))
|
||||
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||
of mExpr: setMagicType(m, tyExpr, 0)
|
||||
of mStmt: setMagicType(m, tyStmt, 0)
|
||||
of mExpr:
|
||||
if m.name.s == "auto":
|
||||
setMagicType(m, tyAnything, 0)
|
||||
else:
|
||||
setMagicType(m, tyExpr, 0)
|
||||
if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
|
||||
of mStmt:
|
||||
setMagicType(m, tyStmt, 0)
|
||||
if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
|
||||
of mTypeDesc:
|
||||
setMagicType(m, tyTypeDesc, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mVoidType: setMagicType(m, tyEmpty, 0)
|
||||
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
|
||||
of mArray:
|
||||
setMagicType(m, tyArray, 0)
|
||||
of mOpenArray:
|
||||
|
|
@ -1348,7 +1386,8 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
of mOrdinal:
|
||||
setMagicType(m, tyOrdinal, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mPNimrodNode: discard
|
||||
of mPNimrodNode:
|
||||
incl m.typ.flags, tfTriggersCompileTime
|
||||
of mShared:
|
||||
setMagicType(m, tyObject, 0)
|
||||
m.typ.n = newNodeI(nkRecList, m.info)
|
||||
|
|
|
|||
|
|
@ -75,8 +75,12 @@ proc searchInstTypes*(key: PType): PType =
|
|||
proc cacheTypeInst*(inst: PType) =
|
||||
# XXX: add to module's generics
|
||||
# update the refcount
|
||||
let genericTyp = inst.sons[0]
|
||||
genericTyp.sym.typeInstCache.safeAdd(inst)
|
||||
let gt = inst.sons[0]
|
||||
let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
|
||||
if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
|
||||
return
|
||||
gt.sym.typeInstCache.safeAdd(inst)
|
||||
|
||||
|
||||
type
|
||||
TReplTypeVars* {.final.} = object
|
||||
|
|
@ -90,6 +94,8 @@ type
|
|||
allowMetaTypes*: bool # allow types such as seq[Number]
|
||||
# i.e. the result contains unresolved generics
|
||||
skipTypedesc*: bool # wether we should skip typeDescs
|
||||
owner*: PSym # where this instantiation comes from
|
||||
recursionLimit: int
|
||||
|
||||
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
|
||||
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||
|
|
@ -207,6 +213,9 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
|
|||
|
||||
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||
if s == nil: return nil
|
||||
# symbol is not our business:
|
||||
if cl.owner != nil and s.owner != cl.owner:
|
||||
return s
|
||||
result = PSym(idTableGet(cl.symMap, s))
|
||||
if result == nil:
|
||||
result = copySym(s, false)
|
||||
|
|
@ -365,6 +374,19 @@ proc propagateFieldFlags(t: PType, n: PNode) =
|
|||
else: discard
|
||||
|
||||
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
template bailout =
|
||||
if cl.recursionLimit > 100:
|
||||
# bail out, see bug #2509. But note this caching is in general wrong,
|
||||
# look at this example where TwoVectors should not share the generic
|
||||
# instantiations (bug #3112):
|
||||
|
||||
# type
|
||||
# Vector[N: static[int]] = array[N, float64]
|
||||
# TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
if result != nil: return result
|
||||
inc cl.recursionLimit
|
||||
|
||||
result = t
|
||||
if t == nil: return
|
||||
|
||||
|
|
@ -420,8 +442,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
result = t
|
||||
|
||||
of tyGenericInst:
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
if result != nil: return result
|
||||
bailout()
|
||||
result = instCopyType(cl, t)
|
||||
idTablePut(cl.localCache, t, result)
|
||||
for i in 1 .. <result.sonsLen:
|
||||
|
|
@ -431,8 +452,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
else:
|
||||
if containsGenericType(t):
|
||||
#if not cl.allowMetaTypes:
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
if result != nil: return result
|
||||
bailout()
|
||||
result = instCopyType(cl, t)
|
||||
result.size = -1 # needs to be recomputed
|
||||
#if not cl.allowMetaTypes:
|
||||
|
|
@ -440,8 +460,14 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
|
||||
for i in countup(0, sonsLen(result) - 1):
|
||||
if result.sons[i] != nil:
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
var r = replaceTypeVarsT(cl, result.sons[i])
|
||||
if result.kind == tyObject:
|
||||
# carefully coded to not skip the precious tyGenericInst:
|
||||
let r2 = r.skipTypes({tyGenericInst})
|
||||
if r2.kind in {tyPtr, tyRef}:
|
||||
r = skipTypes(r2, {tyPtr, tyRef})
|
||||
result.sons[i] = r
|
||||
propagateToOwner(result, r)
|
||||
|
||||
result.n = replaceTypeVarsN(cl, result.n)
|
||||
|
||||
|
|
@ -459,22 +485,33 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
|
||||
else: discard
|
||||
|
||||
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
|
||||
proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
|
||||
owner: PSym): TReplTypeVars =
|
||||
initIdTable(result.symMap)
|
||||
copyIdTable(result.typeMap, pt)
|
||||
initIdTable(result.localCache)
|
||||
result.info = info
|
||||
result.c = p
|
||||
result.owner = owner
|
||||
|
||||
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
var cl = initTypeVars(p, pt, n.info)
|
||||
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
||||
owner: PSym): PNode =
|
||||
var cl = initTypeVars(p, pt, n.info, owner)
|
||||
pushInfoContext(n.info)
|
||||
result = replaceTypeVarsN(cl, n)
|
||||
popInfoContext()
|
||||
|
||||
proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
|
||||
original, new: PSym): PNode =
|
||||
var cl = initTypeVars(p, pt, n.info, original)
|
||||
idTablePut(cl.symMap, original, new)
|
||||
pushInfoContext(n.info)
|
||||
result = replaceTypeVarsN(cl, n)
|
||||
popInfoContext()
|
||||
|
||||
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
t: PType): PType =
|
||||
var cl = initTypeVars(p, pt, info)
|
||||
var cl = initTypeVars(p, pt, info, nil)
|
||||
pushInfoContext(info)
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ when useCaas:
|
|||
|
||||
# We cache modules and the dependency graph. However, we don't check for
|
||||
# file changes but expect the client to tell us about them, otherwise the
|
||||
# repeated CRC calculations may turn out to be too slow.
|
||||
# repeated hash calculations may turn out to be too slow.
|
||||
|
||||
var
|
||||
curCaasCmd* = ""
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ type
|
|||
coerceDistincts*: bool # this is an explicit coercion that can strip away
|
||||
# a distrinct type
|
||||
typedescMatched*: bool
|
||||
isNoCall*: bool # misused for generic type instantiations C[T]
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||
# user if overload resolution fails
|
||||
|
|
@ -57,6 +58,10 @@ type
|
|||
isSubtype,
|
||||
isSubrange, # subrange of the wanted type; no type conversion
|
||||
# but apart from that counts as ``isSubtype``
|
||||
isBothMetaConvertible # generic proc parameter was matched against
|
||||
# generic type, e.g., map(mySeq, x=>x+1),
|
||||
# maybe recoverable by rerun if the parameter is
|
||||
# the proc's return value
|
||||
isInferred, # generic proc was matched against a concrete type
|
||||
isInferredConvertible, # same as above, but requiring proc CC conversion
|
||||
isGeneric,
|
||||
|
|
@ -158,11 +163,15 @@ proc sumGeneric(t: PType): int =
|
|||
t = t.sons[0]
|
||||
inc result
|
||||
inc isvar
|
||||
of tyTypeDesc:
|
||||
t = t.lastSon
|
||||
if t.kind == tyEmpty: break
|
||||
inc result
|
||||
of tyGenericInvocation, tyTuple:
|
||||
result += ord(t.kind == tyGenericInvocation)
|
||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||
break
|
||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||
of tyGenericParam, tyExpr, tyStatic, tyStmt: break
|
||||
of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
|
||||
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64:
|
||||
|
|
@ -218,12 +227,12 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
|||
result = complexDisambiguation(a.callee, b.callee)
|
||||
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
writeln(stdout, "exact matches: " & $c.exactMatches)
|
||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||
writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
writeln(stdout, "conv matches: " & $c.convMatches)
|
||||
writeln(stdout, "inheritance: " & $c.inheritancePenalty)
|
||||
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
||||
writeLine(stdout, "generic matches: " & $c.genericMatches)
|
||||
writeLine(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
writeLine(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
writeLine(stdout, "conv matches: " & $c.convMatches)
|
||||
writeLine(stdout, "inheritance: " & $c.inheritancePenalty)
|
||||
|
||||
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||
if arg.kind in nkSymChoices:
|
||||
|
|
@ -264,6 +273,9 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
|||
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
||||
of tyNil:
|
||||
result = nil # what should it be?
|
||||
of tyTypeDesc:
|
||||
if c.isNoCall: result = t
|
||||
else: result = nil
|
||||
of tySequence, tySet:
|
||||
if t.sons[0].kind == tyEmpty: result = nil
|
||||
else: result = t
|
||||
|
|
@ -381,8 +393,29 @@ proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
|||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||
|
||||
proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
var f = f
|
||||
## For example we have:
|
||||
## .. code-block:: nim
|
||||
## proc myMap[T,S](sIn: seq[T], f: proc(x: T): S): seq[S] = ...
|
||||
## proc innerProc[Q,W](q: Q): W = ...
|
||||
## And we want to match: myMap(@[1,2,3], innerProc)
|
||||
## This proc (procParamTypeRel) will do the following steps in
|
||||
## three different calls:
|
||||
## - matches f=T to a=Q. Since f is metatype, we resolve it
|
||||
## to int (which is already known at this point). So in this case
|
||||
## Q=int mapping will be saved to c.bindings.
|
||||
## - matches f=S to a=W. Both of these metatypes are unknown, so we
|
||||
## return with isBothMetaConvertible to ask for rerun.
|
||||
## - matches f=S to a=W. At this point the return type of innerProc
|
||||
## is known (we get it from c.bindings). We can use that value
|
||||
## to match with f, and save back to c.bindings.
|
||||
var
|
||||
f = f
|
||||
a = a
|
||||
|
||||
if a.isMetaType:
|
||||
let aResolved = PType(idTableGet(c.bindings, a))
|
||||
if aResolved != nil:
|
||||
a = aResolved
|
||||
if a.isMetaType:
|
||||
if f.isMetaType:
|
||||
# We are matching a generic proc (as proc param)
|
||||
|
|
@ -393,12 +426,15 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
|
||||
if f == nil or f.isMetaType:
|
||||
# no luck resolving the type, so the inference fails
|
||||
return isNone
|
||||
return isBothMetaConvertible
|
||||
# Note that this typeRel call will save a's resolved type into c.bindings
|
||||
let reverseRel = typeRel(c, a, f)
|
||||
if reverseRel >= isGeneric:
|
||||
result = isInferred
|
||||
#inc c.genericMatches
|
||||
else:
|
||||
# Note that this typeRel call will save f's resolved type into c.bindings
|
||||
# if f is metatype.
|
||||
result = typeRel(c, f, a)
|
||||
|
||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||
|
|
@ -442,8 +478,9 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
elif f.callConv != a.callConv:
|
||||
# valid to pass a 'nimcall' thingie to 'closure':
|
||||
if f.callConv == ccClosure and a.callConv == ccDefault:
|
||||
result = if result != isInferred: isConvertible
|
||||
else: isInferredConvertible
|
||||
result = if result == isInferred: isInferredConvertible
|
||||
elif result == isBothMetaConvertible: isBothMetaConvertible
|
||||
else: isConvertible
|
||||
else:
|
||||
return isNone
|
||||
when useEffectSystem:
|
||||
|
|
@ -474,6 +511,9 @@ 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:
|
||||
localError(body.n[3].info, $body.n[3] & " too nested for type matching")
|
||||
return isNone
|
||||
|
||||
openScope(c)
|
||||
inc c.inTypeClass
|
||||
|
|
@ -553,7 +593,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
|
|||
# Here, N-1 will be initially nkStaticExpr that can be evaluated only after
|
||||
# N is bound to a concrete value during the matching of the first param.
|
||||
# This proc is used to evaluate such static expressions.
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n)
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
|
@ -644,6 +684,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyAnything:
|
||||
return if f.kind == tyAnything: isGeneric
|
||||
else: isNone
|
||||
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||
# is a concept too (tgraph)
|
||||
let x = typeRel(c, a, f, false)
|
||||
if x >= isGeneric:
|
||||
return isGeneric
|
||||
else: discard
|
||||
|
||||
case f.kind
|
||||
|
|
@ -727,8 +774,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isNone
|
||||
else: discard
|
||||
of tyOpenArray, tyVarargs:
|
||||
# varargs[expr] is special
|
||||
if f.kind == tyVarargs and f.sons[0].kind == tyExpr: return
|
||||
# varargs[expr] is special too but handled earlier. So we only need to
|
||||
# handle varargs[stmt] which is the same as varargs[typed]:
|
||||
if f.kind == tyVarargs:
|
||||
if tfOldSchoolExprStmt in f.sons[0].flags:
|
||||
if f.sons[0].kind == tyExpr: return
|
||||
elif f.sons[0].kind == tyStmt: return
|
||||
case a.kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = typeRel(c, base(f), base(a))
|
||||
|
|
@ -748,6 +799,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isConvertible
|
||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
||||
result = isConvertible
|
||||
of tyString:
|
||||
if f.kind == tyOpenArray:
|
||||
if f.sons[0].kind == tyChar:
|
||||
result = isConvertible
|
||||
elif f.sons[0].kind == tyGenericParam and a.len > 0 and
|
||||
typeRel(c, base(f), base(a)) >= isGeneric:
|
||||
result = isConvertible
|
||||
else: discard
|
||||
of tySequence:
|
||||
case a.kind
|
||||
|
|
@ -1091,6 +1149,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = isNone
|
||||
|
||||
of tyStmt:
|
||||
if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
|
||||
put(c.bindings, f, aOrig)
|
||||
result = isGeneric
|
||||
|
||||
of tyProxy:
|
||||
|
|
@ -1204,7 +1264,7 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
|||
case r
|
||||
of isConvertible, isIntConv: inc(m.convMatches, convMatch)
|
||||
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||
of isGeneric, isInferred: inc(m.genericMatches)
|
||||
of isGeneric, isInferred, isBothMetaConvertible: inc(m.genericMatches)
|
||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||
of isInferredConvertible:
|
||||
inc(m.convMatches)
|
||||
|
|
@ -1270,6 +1330,29 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
put(m.bindings, f, inlined)
|
||||
return argSemantized
|
||||
|
||||
# If r == isBothMetaConvertible then we rerun typeRel.
|
||||
# bothMetaCounter is for safety to avoid any infinite loop,
|
||||
# I don't have any example when it is needed.
|
||||
# lastBindingsLenth is used to check whether m.bindings remains the same,
|
||||
# because in that case there is no point in continuing.
|
||||
var bothMetaCounter = 0
|
||||
var lastBindingsLength = -1
|
||||
while r == isBothMetaConvertible and
|
||||
lastBindingsLength != m.bindings.counter and
|
||||
bothMetaCounter < 100:
|
||||
lastBindingsLength = m.bindings.counter
|
||||
inc(bothMetaCounter)
|
||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||
result = c.semInferredLambda(c, m.bindings, arg)
|
||||
elif arg.kind != nkSym:
|
||||
return nil
|
||||
else:
|
||||
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
|
||||
result = newSymNode(inferred, arg.info)
|
||||
inc(m.convMatches)
|
||||
arg = result
|
||||
r = typeRel(m, f, arg.typ)
|
||||
|
||||
case r
|
||||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
|
|
@ -1281,7 +1364,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
if f.kind == tyTypeDesc:
|
||||
result = arg
|
||||
else:
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
of isSubrange:
|
||||
inc(m.subtypeMatches)
|
||||
if f.kind == tyVar:
|
||||
|
|
@ -1291,6 +1377,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
of isInferred, isInferredConvertible:
|
||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||
result = c.semInferredLambda(c, m.bindings, arg)
|
||||
elif arg.kind != nkSym:
|
||||
return nil
|
||||
else:
|
||||
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
|
||||
result = newSymNode(inferred, arg.info)
|
||||
|
|
@ -1310,6 +1398,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
else:
|
||||
result = arg
|
||||
of isBothMetaConvertible:
|
||||
# This is the result for the 101th time.
|
||||
result = nil
|
||||
of isFromIntLit:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
|
|
@ -1454,6 +1545,10 @@ proc incrIndexType(t: PType) =
|
|||
assert t.kind == tyArrayConstr
|
||||
inc t.sons[0].n.sons[1].intVal
|
||||
|
||||
template isVarargsUntyped(x): expr =
|
||||
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.} =
|
||||
|
|
@ -1482,10 +1577,17 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
var formalLen = m.callee.n.len
|
||||
addSon(m.call, copyTree(n.sons[0]))
|
||||
var container: PNode = nil # constructed container
|
||||
var formal: PSym = nil
|
||||
var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil
|
||||
|
||||
while a < n.len:
|
||||
if n.sons[a].kind == nkExprEqExpr:
|
||||
if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped:
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info))
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
addSon(container, n.sons[a])
|
||||
elif n.sons[a].kind == nkExprEqExpr:
|
||||
# named param
|
||||
# check if m.callee has such a param:
|
||||
prepareNamedParam(n.sons[a])
|
||||
|
|
@ -1507,7 +1609,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
||||
n.sons[a].typ = n.sons[a].sons[1].typ
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a].sons[1], nOrig.sons[a].sons[1])
|
||||
n.sons[a].sons[1], n.sons[a].sons[1])
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
|
|
@ -1536,7 +1638,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
addSon(m.call, copyTree(n.sons[a]))
|
||||
elif formal != nil and formal.typ.kind == tyVarargs:
|
||||
# beware of the side-effects in 'prepareOperand'! So only do it for
|
||||
# varags matching. See tests/metatype/tstatic_overloading.
|
||||
# varargs matching. See tests/metatype/tstatic_overloading.
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
|
|
@ -1599,6 +1701,10 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
|||
matchesAux(c, n, nOrig, m, marker)
|
||||
|
||||
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||
if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}:
|
||||
m.state = csMatch
|
||||
m.call = n
|
||||
return
|
||||
var marker = initIntSet()
|
||||
matchesAux(c, n, nOrig, m, marker)
|
||||
if m.state == csNoMatch: return
|
||||
|
|
|
|||
|
|
@ -15,57 +15,79 @@ import algorithm, sequtils
|
|||
|
||||
const
|
||||
sep = '\t'
|
||||
sectionSuggest = "sug"
|
||||
sectionDef = "def"
|
||||
sectionContext = "con"
|
||||
sectionUsage = "use"
|
||||
|
||||
type
|
||||
Suggest* = object
|
||||
section*: IdeCmd
|
||||
qualifiedPath*: seq[string]
|
||||
filePath*: string
|
||||
line*: int # Starts at 1
|
||||
column*: int # Starts at 0
|
||||
doc*: string # Not escaped (yet)
|
||||
symkind*: TSymKind
|
||||
forth*: string # XXX TODO object on symkind
|
||||
|
||||
var
|
||||
suggestionResultHook*: proc (result: Suggest) {.closure.}
|
||||
|
||||
#template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
|
||||
|
||||
template origModuleName(m: PSym): string = m.name.s
|
||||
|
||||
proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
|
||||
result = section
|
||||
result.add(sep)
|
||||
proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest =
|
||||
result.section = parseIdeCmd(section)
|
||||
if optIdeTerse in gGlobalOptions:
|
||||
if s.kind in routineKinds:
|
||||
result.add renderTree(s.ast, {renderNoBody, renderNoComments,
|
||||
renderDocComments, renderNoPragmas})
|
||||
else:
|
||||
result.add s.name.s
|
||||
result.add(sep)
|
||||
result.add(toFullPath(li))
|
||||
result.add(sep)
|
||||
result.add($toLinenumber(li))
|
||||
result.add(sep)
|
||||
result.add($toColumn(li))
|
||||
result.symkind = s.kind
|
||||
result.filePath = toFullPath(li)
|
||||
result.line = toLinenumber(li)
|
||||
result.column = toColumn(li)
|
||||
else:
|
||||
result.add($s.kind)
|
||||
result.add(sep)
|
||||
result.symkind = s.kind
|
||||
result.qualifiedPath = @[]
|
||||
if not isLocal and s.kind != skModule:
|
||||
let ow = s.owner
|
||||
if ow.kind != skModule and ow.owner != nil:
|
||||
let ow2 = ow.owner
|
||||
result.add(ow2.origModuleName)
|
||||
result.add('.')
|
||||
result.add(ow.origModuleName)
|
||||
result.add('.')
|
||||
result.add(s.name.s)
|
||||
result.add(sep)
|
||||
if s.typ != nil:
|
||||
result.add(typeToString(s.typ))
|
||||
result.add(sep)
|
||||
result.add(toFullPath(li))
|
||||
result.add(sep)
|
||||
result.add($toLinenumber(li))
|
||||
result.add(sep)
|
||||
result.add($toColumn(li))
|
||||
result.add(sep)
|
||||
when not defined(noDocgen):
|
||||
result.add(s.extractDocComment.escape)
|
||||
result.qualifiedPath.add(ow2.origModuleName)
|
||||
result.qualifiedPath.add(ow.origModuleName)
|
||||
result.qualifiedPath.add(s.name.s)
|
||||
|
||||
proc symToStr(s: PSym, isLocal: bool, section: string): string =
|
||||
result = symToStr(s, isLocal, section, s.info)
|
||||
if s.typ != nil:
|
||||
result.forth = typeToString(s.typ)
|
||||
else:
|
||||
result.forth = ""
|
||||
result.filePath = toFullPath(li)
|
||||
result.line = toLinenumber(li)
|
||||
result.column = toColumn(li)
|
||||
when not defined(noDocgen):
|
||||
result.doc = s.extractDocComment
|
||||
|
||||
proc `$`(suggest: Suggest): string =
|
||||
result = $suggest.section
|
||||
result.add(sep)
|
||||
result.add($suggest.symkind)
|
||||
result.add(sep)
|
||||
result.add(suggest.qualifiedPath.join("."))
|
||||
result.add(sep)
|
||||
result.add(suggest.forth)
|
||||
result.add(sep)
|
||||
result.add(suggest.filePath)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
when not defined(noDocgen):
|
||||
result.add(suggest.doc.escape)
|
||||
|
||||
proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest =
|
||||
result = symToSuggest(s, isLocal, section, s.info)
|
||||
|
||||
proc suggestResult(s: Suggest) =
|
||||
if not isNil(suggestionResultHook):
|
||||
suggestionResultHook(s)
|
||||
else:
|
||||
suggestWriteln($(s))
|
||||
|
||||
proc filterSym(s: PSym): bool {.inline.} =
|
||||
result = s.kind != skModule
|
||||
|
|
@ -82,9 +104,9 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
|
|||
result = true
|
||||
break
|
||||
|
||||
proc suggestField(c: PContext, s: PSym, outputs: var int) =
|
||||
proc suggestField(c: PContext, s: PSym, outputs: var int) =
|
||||
if filterSym(s) and fieldVisible(c, s):
|
||||
suggestWriteln(symToStr(s, isLocal=true, sectionSuggest))
|
||||
suggestResult(symToSuggest(s, isLocal=true, $ideSug))
|
||||
inc outputs
|
||||
|
||||
template wholeSymTab(cond, section: expr) {.immediate.} =
|
||||
|
|
@ -97,20 +119,20 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
|
|||
for item in entries:
|
||||
let it {.inject.} = item
|
||||
if cond:
|
||||
suggestWriteln(symToStr(it, isLocal = isLocal, section))
|
||||
suggestResult(symToSuggest(it, isLocal = isLocal, section))
|
||||
inc outputs
|
||||
|
||||
proc suggestSymList(c: PContext, list: PNode, outputs: var int) =
|
||||
for i in countup(0, sonsLen(list) - 1):
|
||||
proc suggestSymList(c: PContext, list: PNode, outputs: var int) =
|
||||
for i in countup(0, sonsLen(list) - 1):
|
||||
if list.sons[i].kind == nkSym:
|
||||
suggestField(c, list.sons[i].sym, outputs)
|
||||
#else: InternalError(list.info, "getSymFromList")
|
||||
|
||||
proc suggestObject(c: PContext, n: PNode, outputs: var int) =
|
||||
proc suggestObject(c: PContext, n: PNode, outputs: var int) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], outputs)
|
||||
of nkRecCase:
|
||||
of nkRecCase:
|
||||
var L = sonsLen(n)
|
||||
if L > 0:
|
||||
suggestObject(c, n.sons[0], outputs)
|
||||
|
|
@ -118,7 +140,7 @@ proc suggestObject(c: PContext, n: PNode, outputs: var int) =
|
|||
of nkSym: suggestField(c, n.sym, outputs)
|
||||
else: discard
|
||||
|
||||
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
|
||||
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
|
||||
var op = n.sons[0]
|
||||
if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op.sons[0]
|
||||
var opr: PIdent
|
||||
|
|
@ -128,8 +150,8 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool =
|
|||
else: return false
|
||||
result = opr.id == s.name.id
|
||||
|
||||
proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
|
||||
case candidate.kind
|
||||
proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
|
||||
case candidate.kind
|
||||
of OverloadableSyms:
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, candidate, nil)
|
||||
|
|
@ -138,11 +160,11 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
|
|||
else:
|
||||
result = false
|
||||
|
||||
proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) =
|
||||
proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) =
|
||||
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
|
||||
sectionContext)
|
||||
$ideCon)
|
||||
|
||||
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
||||
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
||||
if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
|
||||
# special rule: if system and some weird generic match via 'tyExpr'
|
||||
# or 'tyGenericParam' we won't list it either to reduce the noise (nobody
|
||||
|
|
@ -157,7 +179,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
|
|||
|
||||
proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
|
||||
assert typ != nil
|
||||
wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest)
|
||||
wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), $ideSug)
|
||||
|
||||
proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
|
||||
# do not produce too many symbols:
|
||||
|
|
@ -166,7 +188,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
|
|||
if scope == c.topLevelScope: isLocal = false
|
||||
for it in items(scope.symbols):
|
||||
if filterSym(it):
|
||||
suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest))
|
||||
suggestResult(symToSuggest(it, isLocal = isLocal, $ideSug))
|
||||
inc outputs
|
||||
if scope == c.topLevelScope: break
|
||||
|
||||
|
|
@ -176,48 +198,48 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
|
|||
var typ = n.typ
|
||||
if typ == nil:
|
||||
# a module symbol has no type for example:
|
||||
if n.kind == nkSym and n.sym.kind == skModule:
|
||||
if n.sym == c.module:
|
||||
if n.kind == nkSym and n.sym.kind == skModule:
|
||||
if n.sym == c.module:
|
||||
# all symbols accessible, because we are in the current module:
|
||||
for it in items(c.topLevelScope.symbols):
|
||||
if filterSym(it):
|
||||
suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
|
||||
if filterSym(it):
|
||||
suggestResult(symToSuggest(it, isLocal=false, $ideSug))
|
||||
inc outputs
|
||||
else:
|
||||
for it in items(n.sym.tab):
|
||||
if filterSym(it):
|
||||
suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
|
||||
else:
|
||||
for it in items(n.sym.tab):
|
||||
if filterSym(it):
|
||||
suggestResult(symToSuggest(it, isLocal=false, $ideSug))
|
||||
inc outputs
|
||||
else:
|
||||
# fallback:
|
||||
suggestEverything(c, n, outputs)
|
||||
elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType:
|
||||
elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType:
|
||||
# look up if the identifier belongs to the enum:
|
||||
var t = typ
|
||||
while t != nil:
|
||||
while t != nil:
|
||||
suggestSymList(c, t.n, outputs)
|
||||
t = t.sons[0]
|
||||
suggestOperations(c, n, typ, outputs)
|
||||
else:
|
||||
typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
if typ.kind == tyObject:
|
||||
if typ.kind == tyObject:
|
||||
var t = typ
|
||||
while true:
|
||||
while true:
|
||||
suggestObject(c, t.n, outputs)
|
||||
if t.sons[0] == nil: break
|
||||
if t.sons[0] == nil: break
|
||||
t = skipTypes(t.sons[0], {tyGenericInst})
|
||||
suggestOperations(c, n, typ, outputs)
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
suggestSymList(c, typ.n, outputs)
|
||||
suggestOperations(c, n, typ, outputs)
|
||||
else:
|
||||
suggestOperations(c, n, typ, outputs)
|
||||
|
||||
type
|
||||
TCheckPointResult = enum
|
||||
TCheckPointResult = enum
|
||||
cpNone, cpFuzzy, cpExact
|
||||
|
||||
proc inCheckpoint(current: TLineInfo): TCheckPointResult =
|
||||
proc inCheckpoint(current: TLineInfo): TCheckPointResult =
|
||||
if current.fileIndex == gTrackPos.fileIndex:
|
||||
if current.line == gTrackPos.line and
|
||||
abs(current.col-gTrackPos.col) < 4:
|
||||
|
|
@ -233,8 +255,8 @@ proc findClosestDot(n: PNode): PNode =
|
|||
result = findClosestDot(n.sons[i])
|
||||
if result != nil: return
|
||||
|
||||
proc findClosestCall(n: PNode): PNode =
|
||||
if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact:
|
||||
proc findClosestCall(n: PNode): PNode =
|
||||
if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact:
|
||||
result = n
|
||||
else:
|
||||
for i in 0.. <safeLen(n):
|
||||
|
|
@ -248,8 +270,8 @@ proc isTracked(current: TLineInfo, tokenLen: int): bool =
|
|||
if col >= current.col and col <= current.col+tokenLen-1:
|
||||
return true
|
||||
|
||||
proc findClosestSym(n: PNode): PNode =
|
||||
if n.kind == nkSym and inCheckpoint(n.info) == cpExact:
|
||||
proc findClosestSym(n: PNode): PNode =
|
||||
if n.kind == nkSym and inCheckpoint(n.info) == cpExact:
|
||||
result = n
|
||||
elif n.kind notin {nkNone..nkNilLit}:
|
||||
for i in 0.. <sonsLen(n):
|
||||
|
|
@ -263,16 +285,16 @@ var
|
|||
proc findUsages(info: TLineInfo; s: PSym) =
|
||||
if usageSym == nil and isTracked(info, s.name.s.len):
|
||||
usageSym = s
|
||||
suggestWriteln(symToStr(s, isLocal=false, sectionUsage))
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideUse))
|
||||
elif s == usageSym:
|
||||
if lastLineInfo != info:
|
||||
suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info))
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideUse, info))
|
||||
lastLineInfo = info
|
||||
|
||||
proc findDefinition(info: TLineInfo; s: PSym) =
|
||||
if s.isNil: return
|
||||
if isTracked(info, s.name.s.len):
|
||||
suggestWriteln(symToStr(s, isLocal=false, sectionDef))
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideDef))
|
||||
suggestQuit()
|
||||
|
||||
proc ensureIdx[T](x: var T, y: int) =
|
||||
|
|
@ -287,6 +309,10 @@ proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
|
|||
findUsages(info, s)
|
||||
elif gIdeCmd == ideDef:
|
||||
findDefinition(info, s)
|
||||
elif gIdeCmd == ideDus and s != nil:
|
||||
if isTracked(info, s.name.s.len):
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideDef))
|
||||
findUsages(info, s)
|
||||
|
||||
proc markUsed(info: TLineInfo; s: PSym) =
|
||||
incl(s.flags, sfUsed)
|
||||
|
|
@ -306,15 +332,15 @@ proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
|||
except ERecoverableError:
|
||||
result = ast.emptyNode
|
||||
|
||||
proc suggestExpr*(c: PContext, node: PNode) =
|
||||
proc suggestExpr*(c: PContext, node: PNode) =
|
||||
if nfIsCursor notin node.flags:
|
||||
if gTrackPos.line < 0: return
|
||||
var cp = inCheckpoint(node.info)
|
||||
if cp == cpNone: return
|
||||
var outputs = 0
|
||||
# This keeps semExpr() from coming here recursively:
|
||||
if c.inCompilesContext > 0: return
|
||||
inc(c.inCompilesContext)
|
||||
if c.compilesContextId > 0: return
|
||||
inc(c.compilesContextId)
|
||||
|
||||
if gIdeCmd == ideSug:
|
||||
var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
|
||||
|
|
@ -327,7 +353,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
|||
#writeStackTrace()
|
||||
else:
|
||||
suggestEverything(c, n, outputs)
|
||||
|
||||
|
||||
elif gIdeCmd == ideCon:
|
||||
var n = if nfIsCursor in node.flags: node else: findClosestCall(node)
|
||||
if n == nil: n = node
|
||||
|
|
@ -342,9 +368,9 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
|||
if x.kind == nkEmpty or x.typ == nil: break
|
||||
addSon(a, x)
|
||||
suggestCall(c, a, n, outputs)
|
||||
|
||||
dec(c.inCompilesContext)
|
||||
if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
|
||||
|
||||
proc suggestStmt*(c: PContext, n: PNode) =
|
||||
dec(c.compilesContextId)
|
||||
if outputs > 0 and gIdeCmd notin {ideUse, ideDus}: suggestQuit()
|
||||
|
||||
proc suggestStmt*(c: PContext, n: PNode) =
|
||||
suggestExpr(c, n)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue