Merge branch 'devel' into gogc
This commit is contained in:
commit
bdac85f2cf
212 changed files with 8304 additions and 7492 deletions
|
|
@ -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
|
||||
|
|
@ -423,6 +423,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
|
||||
|
|
@ -538,22 +539,21 @@ type
|
|||
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,
|
||||
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,
|
||||
mUnaryMinusI64, mAbsI, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
|
|
@ -593,20 +593,19 @@ const
|
|||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
|
||||
mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI,
|
||||
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,
|
||||
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,
|
||||
mUnaryMinusI64, mAbsI, mNot,
|
||||
mUnaryPlusI, mBitnotI,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
|
|
@ -842,7 +841,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 +946,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 =
|
||||
|
|
@ -1345,7 +1347,7 @@ proc propagateToOwner*(owner, elem: PType) =
|
|||
owner.flags.incl tfHasAsgn
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1661,7 +1652,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)
|
||||
|
|
@ -2150,7 +2141,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", [])
|
||||
|
|
|
|||
|
|
@ -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.`%`
|
||||
|
||||
|
|
@ -721,6 +720,8 @@ 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 hasAttribute in CC[cCompiler].props:
|
||||
|
|
|
|||
|
|
@ -537,6 +537,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "genscript":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optGenScript)
|
||||
of "usecolors":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optUseColors)
|
||||
of "lib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
libpath = processPath(arg, notRelativeToProj=true)
|
||||
|
|
|
|||
|
|
@ -88,3 +88,4 @@ proc initDefines*() =
|
|||
defineSymbol("nimalias")
|
||||
defineSymbol("nimlocks")
|
||||
defineSymbol("nimnode")
|
||||
defineSymbol("nimnomagic64")
|
||||
|
|
|
|||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
# nim files.
|
||||
|
||||
import
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
securehash
|
||||
|
||||
type
|
||||
TSystemCC* = enum
|
||||
|
|
@ -572,26 +573,24 @@ 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 currentCrc = footprint(filename)
|
||||
var f: File
|
||||
if open(f, crcFile, fmRead):
|
||||
var line = newStringOfCap(40)
|
||||
if not f.readLine(line): line = "0"
|
||||
let oldCrc = parseSecureHash(f.readLine())
|
||||
close(f)
|
||||
var oldCrc = parseInt(line)
|
||||
result = oldCrc != currentCrc
|
||||
else:
|
||||
result = true
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
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.} =
|
||||
|
|
|
|||
|
|
@ -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,11 +30,11 @@ 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}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
# id. This module is essential for the compiler's performance.
|
||||
|
||||
import
|
||||
hashes, strutils
|
||||
hashes, strutils, etcpriv
|
||||
|
||||
type
|
||||
TIdObj* = object of RootObj
|
||||
|
|
@ -23,7 +23,7 @@ type
|
|||
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,6 +37,8 @@ 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]
|
||||
|
|
@ -65,7 +67,7 @@ proc cmpExact(a, b: cstring, blen: int): int =
|
|||
|
||||
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
|
||||
|
|
@ -99,7 +101,7 @@ 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 =
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ 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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -817,7 +787,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
|||
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, "$1 = nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyBaseIndex:
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
|
|
@ -976,16 +946,28 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
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 & ')')
|
||||
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 & ')')
|
||||
else: internalError(n.sons[0].info, "genAddr")
|
||||
|
||||
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
|
||||
case s.kind
|
||||
|
|
@ -1021,13 +1003,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)
|
||||
|
|
@ -1202,7 +1179,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 != {}:
|
||||
|
|
@ -1394,6 +1371,9 @@ 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)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
||||
|
|
|
|||
|
|
@ -946,7 +946,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
|
||||
|
|
|
|||
|
|
@ -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 @@
|
|||
## implements the module handling
|
||||
|
||||
import
|
||||
ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
|
||||
ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
|
||||
idents, os, lexer, idgen, passes, syntaxes, llstream
|
||||
|
||||
type
|
||||
|
|
@ -19,7 +19,7 @@ type
|
|||
|
||||
TModuleInMemory* = object
|
||||
compiledAt*: float
|
||||
crc*: TCrc32
|
||||
crc*: SecureHash
|
||||
deps*: seq[int32] ## XXX: slurped files are currently not tracked
|
||||
needsRecompile*: TNeedRecompile
|
||||
crcStatus*: TCrcStatus
|
||||
|
|
@ -51,19 +51,19 @@ proc crcChanged(fileIdx: int32): bool =
|
|||
of crcNotChanged:
|
||||
result = false
|
||||
of crcCached:
|
||||
let newCrc = crcFromFile(fileIdx.toFilename)
|
||||
let newCrc = secureHashFile(fileIdx.toFullPath)
|
||||
result = newCrc != gMemCacheData[fileIdx].crc
|
||||
gMemCacheData[fileIdx].crc = newCrc
|
||||
updateStatus()
|
||||
of crcNotTaken:
|
||||
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
|
||||
gMemCacheData[fileIdx].crc = 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)
|
||||
gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFullPath)
|
||||
|
||||
proc addDep(x: PSym, dep: int32) =
|
||||
growCache gMemCacheData, dep
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#
|
||||
|
||||
import
|
||||
options, strutils, os, tables, ropes, platform
|
||||
options, strutils, os, tables, ropes, platform, terminal
|
||||
|
||||
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,
|
||||
|
|
@ -35,7 +34,9 @@ type
|
|||
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,
|
||||
|
|
@ -143,6 +144,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",
|
||||
|
|
@ -190,6 +192,8 @@ 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\'",
|
||||
|
|
@ -601,13 +605,13 @@ 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"
|
||||
PosErrorFormat* = "$1($2, $3) Error: "
|
||||
PosWarningFormat* = "$1($2, $3) Warning: "
|
||||
PosHintFormat* = "$1($2, $3) Hint: "
|
||||
PosContextFormat = "$1($2, $3) Info: "
|
||||
RawError* = "Error: "
|
||||
RawWarning* = "Warning: "
|
||||
RawHint* = "Hint: "
|
||||
|
||||
proc getInfoContextLen*(): int = return msgContext.len
|
||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||
|
|
@ -682,17 +686,27 @@ proc outWriteln*(s: string) =
|
|||
## Writes to stdout. Always.
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
|
||||
proc msgWriteln*(s: string) =
|
||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||
proc msgWriteln*(s: string, color: ForegroundColor = fgWhite, coloredText: string = "") =
|
||||
## Writes to stdout. If --stderr option is given, writes to stderr instead.
|
||||
|
||||
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
var hasColor = optUseColors in gGlobalOptions
|
||||
if not isNil(writelnHook):
|
||||
writelnHook(s)
|
||||
elif optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs: writeln(stderr, s)
|
||||
writelnHook(coloredText & s)
|
||||
else:
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
if optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs:
|
||||
if hasColor: setForegroundColor(color)
|
||||
write(stderr, coloredText)
|
||||
if hasColor: resetAttributes()
|
||||
writeln(stderr, s)
|
||||
else:
|
||||
if eStdOut in errorOutputs:
|
||||
if hasColor: setForegroundColor(color)
|
||||
write(stdout, coloredText)
|
||||
if hasColor: resetAttributes()
|
||||
writeln(stdout, s)
|
||||
|
||||
proc coordToStr(coord: int): string =
|
||||
if coord == -1: result = "???"
|
||||
|
|
@ -714,7 +728,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
|||
if stackTraceAvailable() and isNil(writelnHook):
|
||||
writeStackTrace()
|
||||
else:
|
||||
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
|
||||
msgWriteln("", 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:
|
||||
|
|
@ -737,34 +751,39 @@ proc writeContext(lastinfo: TLineInfo) =
|
|||
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, "")])
|
||||
coordToStr(msgContext[i].line),
|
||||
coordToStr(msgContext[i].col+1),
|
||||
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
|
||||
frmt: string
|
||||
color: ForegroundColor
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = RawErrorFormat
|
||||
frmt = RawError
|
||||
color = fgRed
|
||||
of warnMin..warnMax:
|
||||
if optWarns notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
writeContext(unknownLineInfo())
|
||||
frmt = RawWarningFormat
|
||||
frmt = RawWarning
|
||||
inc(gWarnCounter)
|
||||
color = fgYellow
|
||||
of hintMin..hintMax:
|
||||
if optHints notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
frmt = RawHintFormat
|
||||
frmt = RawHint
|
||||
inc(gHintCounter)
|
||||
let s = `%`(frmt, `%`(msgKindToString(msg), args))
|
||||
color = fgGreen
|
||||
let s = `%`(msgKindToString(msg), args)
|
||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
||||
msgWriteln(s)
|
||||
msgWriteln(s, color, frmt)
|
||||
handleError(msg, doAbort, s)
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
|
|
@ -785,8 +804,10 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
|||
|
||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling) =
|
||||
var frmt: string
|
||||
var ignoreMsg = false
|
||||
var
|
||||
frmt: string
|
||||
ignoreMsg = false
|
||||
color: ForegroundColor
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
writeContext(info)
|
||||
|
|
@ -795,22 +816,26 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
|||
# in the same file and line are produced:
|
||||
#ignoreMsg = lastError == info and eh != doAbort
|
||||
lastError = info
|
||||
color = fgRed
|
||||
of warnMin..warnMax:
|
||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||
if not ignoreMsg: writeContext(info)
|
||||
frmt = PosWarningFormat
|
||||
inc(gWarnCounter)
|
||||
color = fgYellow
|
||||
of hintMin..hintMax:
|
||||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
frmt = PosHintFormat
|
||||
inc(gHintCounter)
|
||||
color = fgGreen
|
||||
# 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 = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col+1)]
|
||||
let s = getMessageStr(msg, arg)
|
||||
if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
|
||||
msgWriteln(s)
|
||||
msgWriteln(s, color, x)
|
||||
if optPrintSurroundingSrc and msg in errMin..errMax:
|
||||
info.writeSurroundingSrc
|
||||
handleError(msg, eh, s)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -7,330 +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, sequtils, net
|
||||
# Do NOT import suggest. It will lead to wierd bugs with
|
||||
# suggestionResultHook, because suggest.nim is included by sigmatch.
|
||||
# So we import that one instead.
|
||||
import options, commands, modules, sem, passes, passaux, msgs, nimconf,
|
||||
extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
|
||||
|
||||
when defined(windows):
|
||||
import winlean
|
||||
else:
|
||||
import posix
|
||||
|
||||
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
|
||||
--epc use emacs epc mode
|
||||
|
||||
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.
|
||||
"""
|
||||
type
|
||||
Mode = enum mstdin, mtcp, mepc
|
||||
|
||||
var
|
||||
gPort = 6000.Port
|
||||
gAddress = ""
|
||||
gMode: Mode
|
||||
|
||||
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"
|
||||
|
||||
type
|
||||
EUnexpectedCommand = object of Exception
|
||||
|
||||
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 sexp(s: IdeCmd): SexpNode = sexp($s)
|
||||
|
||||
proc sexp(s: TSymKind): SexpNode = sexp($s)
|
||||
|
||||
proc sexp(s: Suggest): SexpNode =
|
||||
# If you change the oder here, make sure to change it over in
|
||||
# nim-mode.el too.
|
||||
result = convertSexp([
|
||||
s.section,
|
||||
s.symkind,
|
||||
s.qualifiedPath.map(newSString),
|
||||
s.filePath,
|
||||
s.forth,
|
||||
s.line,
|
||||
s.column,
|
||||
s.doc
|
||||
])
|
||||
|
||||
proc sexp(s: seq[Suggest]): SexpNode =
|
||||
result = newSList()
|
||||
for sug in s:
|
||||
result.add(sexp(sug))
|
||||
|
||||
proc listEPC(): SexpNode =
|
||||
let
|
||||
argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
|
||||
docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
|
||||
result = newSList()
|
||||
for command in ["sug", "con", "def", "use"]:
|
||||
let
|
||||
cmd = sexp(command)
|
||||
methodDesc = newSList()
|
||||
methodDesc.add(cmd)
|
||||
methodDesc.add(argspecs)
|
||||
methodDesc.add(docstring)
|
||||
result.add(methodDesc)
|
||||
|
||||
proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
|
||||
gIdeCmd = cmd
|
||||
if cmd == ideUse:
|
||||
modules.resetAllModules()
|
||||
var isKnownFile = true
|
||||
let dirtyIdx = file.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)
|
||||
gErrorCounter = 0
|
||||
if not isKnownFile:
|
||||
compileProject()
|
||||
compileProject(dirtyIdx)
|
||||
|
||||
proc executeEPC(cmd: IdeCmd, args: SexpNode) =
|
||||
let
|
||||
file = args[0].getStr
|
||||
line = args[1].getNum
|
||||
column = args[2].getNum
|
||||
var dirtyfile = ""
|
||||
if len(args) > 3:
|
||||
dirtyfile = args[3].getStr(nil)
|
||||
execute(cmd, file, dirtyfile, int(line), int(column))
|
||||
|
||||
proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
|
||||
let response = $convertSexp([newSSymbol(return_symbol), uid, s])
|
||||
socket.send(toHex(len(response), 6))
|
||||
socket.send(response)
|
||||
|
||||
proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
|
||||
result = start
|
||||
while true:
|
||||
try:
|
||||
server.bindaddr(Port(result), host)
|
||||
return
|
||||
except OsError:
|
||||
when defined(windows):
|
||||
let checkFor = WSAEADDRINUSE.OSErrorCode
|
||||
else:
|
||||
let checkFor = EADDRINUSE.OSErrorCode
|
||||
if osLastError() != checkFor:
|
||||
raise getCurrentException()
|
||||
else:
|
||||
result += 1
|
||||
|
||||
proc parseCmdLine(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": 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)
|
||||
|
||||
execute(gIdeCmd, orig, dirtyfile, line, col-1)
|
||||
|
||||
proc serve() =
|
||||
case gMode:
|
||||
of mstdin:
|
||||
echo Help
|
||||
var line = ""
|
||||
while readLineFromStdin("> ", line):
|
||||
parseCmdLine line
|
||||
echo ""
|
||||
flushFile(stdout)
|
||||
of mtcp:
|
||||
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)
|
||||
parseCmdLine inp.string
|
||||
|
||||
stdoutSocket.send("\c\L")
|
||||
stdoutSocket.close()
|
||||
of mepc:
|
||||
var server = newSocket()
|
||||
let port = connectToNextFreePort(server, "localhost")
|
||||
var inp = "".TaintedString
|
||||
server.listen()
|
||||
echo(port)
|
||||
var client = newSocket()
|
||||
# Wait for connection
|
||||
accept(server, client)
|
||||
while true:
|
||||
var sizeHex = ""
|
||||
if client.recv(sizeHex, 6) != 6:
|
||||
raise newException(ValueError, "didn't get all the hexbytes")
|
||||
var size = 0
|
||||
if parseHex(sizeHex, size) == 0:
|
||||
raise newException(ValueError, "invalid size hex: " & $sizeHex)
|
||||
var messageBuffer = ""
|
||||
if client.recv(messageBuffer, size) != size:
|
||||
raise newException(ValueError, "didn't get all the bytes")
|
||||
let
|
||||
message = parseSexp($messageBuffer)
|
||||
messageType = message[0].getSymbol
|
||||
case messageType:
|
||||
of "call":
|
||||
var results: seq[Suggest] = @[]
|
||||
suggestionResultHook = proc (s: Suggest) =
|
||||
results.add(s)
|
||||
|
||||
let
|
||||
uid = message[1].getNum
|
||||
cmd = parseIdeCmd(message[2].getSymbol)
|
||||
args = message[3]
|
||||
executeEPC(cmd, args)
|
||||
returnEPC(client, uid, sexp(results))
|
||||
of "return":
|
||||
raise newException(EUnexpectedCommand, "no return expected")
|
||||
of "return-error":
|
||||
raise newException(EUnexpectedCommand, "no return expected")
|
||||
of "epc-error":
|
||||
stderr.writeln("recieved epc error: " & $messageBuffer)
|
||||
raise newException(IOError, "epc error")
|
||||
of "methods":
|
||||
returnEPC(client, message[1].getNum, listEPC())
|
||||
else:
|
||||
raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
|
||||
|
||||
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)
|
||||
|
||||
# do not stop after the first error:
|
||||
msgs.gErrorMax = high(int)
|
||||
compileProject()
|
||||
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
|
||||
gMode = mtcp
|
||||
of "address":
|
||||
gAddress = p.val
|
||||
gMode = mtcp
|
||||
of "stdin": gMode = mstdin
|
||||
of "epc":
|
||||
gMode = mepc
|
||||
gVerbosity = 0 # Port number gotta be first.
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -54,6 +54,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
|
||||
|
|
@ -145,6 +146,7 @@ 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/
|
||||
|
|
@ -183,8 +185,13 @@ 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 canonicalizePath*(path: string): string =
|
||||
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
@ -499,10 +500,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 +525,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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const
|
|||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||
wTags, wLocks, wGcSafe}
|
||||
exprPragmas* = {wLine, wLocks}
|
||||
exprPragmas* = {wLine, wLocks, wNoRewrite}
|
||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||
|
|
@ -859,6 +859,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
c.module.flags.incl sfExperimental
|
||||
else:
|
||||
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||
of wNoRewrite:
|
||||
noVal(it)
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
|
||||
import
|
||||
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
||||
ropes, idents, crc, idgen, types, rodutils, memfiles
|
||||
ropes, idents, securehash, idgen, types, rodutils, memfiles
|
||||
|
||||
type
|
||||
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
|
||||
|
|
@ -538,10 +538,11 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
|
|||
# else: trigger recompilation:
|
||||
result = true
|
||||
|
||||
proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||
proc processRodFile(r: PRodReader, crc: SecureHash) =
|
||||
var
|
||||
w: string
|
||||
d, inclCrc: int
|
||||
d: int
|
||||
var inclCrc: SecureHash
|
||||
while r.s[r.pos] != '\0':
|
||||
var section = rdWord(r)
|
||||
if r.reason != rrNone:
|
||||
|
|
@ -549,7 +550,8 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
|||
case section
|
||||
of "CRC":
|
||||
inc(r.pos) # skip ':'
|
||||
if int(crc) != decodeVInt(r.s, r.pos): r.reason = rrCrcChange
|
||||
if crc != parseSecureHash(decodeStr(r.s, r.pos)):
|
||||
r.reason = rrCrcChange
|
||||
of "ID":
|
||||
inc(r.pos) # skip ':'
|
||||
r.moduleID = decodeVInt(r.s, r.pos)
|
||||
|
|
@ -596,9 +598,9 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
|||
while r.s[r.pos] != ')':
|
||||
w = r.files[decodeVInt(r.s, r.pos)].toFullPath
|
||||
inc(r.pos) # skip ' '
|
||||
inclCrc = decodeVInt(r.s, r.pos)
|
||||
inclCrc = parseSecureHash(decodeStr(r.s, r.pos))
|
||||
if r.reason == rrNone:
|
||||
if not existsFile(w) or (inclCrc != int(crcFromFile(w))):
|
||||
if not existsFile(w) or (inclCrc != secureHashFile(w)):
|
||||
r.reason = rrInclDeps
|
||||
if r.s[r.pos] == '\x0A':
|
||||
inc(r.pos)
|
||||
|
|
@ -649,7 +651,7 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool =
|
|||
while s < token.len and buf[pos+s] == token[s]: inc s
|
||||
result = s == token.len
|
||||
|
||||
proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
proc newRodReader(modfilename: string, crc: SecureHash,
|
||||
readerIndex: int): PRodReader =
|
||||
new(result)
|
||||
try:
|
||||
|
|
@ -701,7 +703,7 @@ type
|
|||
filename*: string
|
||||
reason*: TReasonForRecompile
|
||||
rd*: PRodReader
|
||||
crc*: TCrc32
|
||||
crc*: SecureHash
|
||||
crcDone*: bool
|
||||
|
||||
TFileModuleMap = seq[TFileModuleRec]
|
||||
|
|
@ -794,13 +796,13 @@ proc loadMethods(r: PRodReader) =
|
|||
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
|
||||
if r.s[r.pos] == ' ': inc(r.pos)
|
||||
|
||||
proc getCRC*(fileIdx: int32): TCrc32 =
|
||||
proc getCRC*(fileIdx: int32): SecureHash =
|
||||
internalAssert fileIdx >= 0 and fileIdx < gMods.len
|
||||
|
||||
if gMods[fileIdx].crcDone:
|
||||
return gMods[fileIdx].crc
|
||||
|
||||
result = crcFromFile(fileIdx.toFilename)
|
||||
result = secureHashFile(fileIdx.toFilename)
|
||||
gMods[fileIdx].crc = result
|
||||
|
||||
template growCache*(cache, pos) =
|
||||
|
|
@ -1017,7 +1019,7 @@ proc writeType(f: File; t: PType) =
|
|||
f.write("]\n")
|
||||
|
||||
proc viewFile(rodfile: string) =
|
||||
var r = newRodReader(rodfile, 0, 0)
|
||||
var r = newRodReader(rodfile, secureHash(""), 0)
|
||||
if r == nil:
|
||||
rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
|
||||
rodfile)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@
|
|||
|
||||
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
|
||||
TRodWriter = object of TPassContext
|
||||
module: PSym
|
||||
crc: TCrc32
|
||||
crc: SecureHash
|
||||
options: TOptions
|
||||
defines: string
|
||||
inclDeps: string
|
||||
|
|
@ -38,7 +39,7 @@ type
|
|||
|
||||
PRodWriter = ref TRodWriter
|
||||
|
||||
proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter
|
||||
proc newRodWriter(crc: SecureHash, module: PSym): PRodWriter
|
||||
proc addModDep(w: PRodWriter, dep: string)
|
||||
proc addInclDep(w: PRodWriter, dep: string)
|
||||
proc addInterfaceSym(w: PRodWriter, s: PSym)
|
||||
|
|
@ -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(crc: SecureHash, module: PSym): PRodWriter =
|
||||
new(result)
|
||||
result.sstack = @[]
|
||||
result.tstack = @[]
|
||||
|
|
@ -96,7 +97,7 @@ 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) =
|
||||
|
|
@ -440,7 +441,7 @@ proc writeRod(w: PRodWriter) =
|
|||
f.write(rodNL)
|
||||
|
||||
var crc = "CRC:"
|
||||
encodeVInt(w.crc, crc)
|
||||
encodeStr($w.crc, crc)
|
||||
f.write(crc)
|
||||
f.write(rodNL)
|
||||
|
||||
|
|
|
|||
199
compiler/securehash.nim
Normal file
199
compiler/securehash.nim
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Nim Contributers
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import
|
||||
strutils, unsigned
|
||||
|
||||
const Sha1DigestSize = 20
|
||||
|
||||
type
|
||||
Sha1Digest = array[0 .. Sha1DigestSize-1, uint8]
|
||||
SecureHash* = distinct Sha1Digest
|
||||
|
||||
proc sha1(src: string) : Sha1Digest
|
||||
|
||||
proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
|
||||
proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
|
||||
proc `$`*(self: SecureHash): string =
|
||||
result = ""
|
||||
for v in Sha1Digest(self):
|
||||
result.add(toHex(int(v), 2))
|
||||
|
||||
proc parseSecureHash*(hash: string): SecureHash =
|
||||
for i in 0.. <Sha1DigestSize:
|
||||
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
|
||||
|
||||
proc `==`*(a, b: SecureHash): bool =
|
||||
# Not a constant-time comparison, but that's acceptable in this context
|
||||
Sha1Digest(a) == Sha1Digest(b)
|
||||
|
||||
|
||||
when isMainModule:
|
||||
let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
|
||||
doAssert hash1 == hash1
|
||||
doAssert parseSecureHash($hash1) == hash1
|
||||
|
||||
|
||||
# Copyright (c) 2011, Micael Hildenborg
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of Micael Hildenborg nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Ported to Nim by Erik O'Leary
|
||||
|
||||
type
|
||||
Sha1State = array[0 .. 5-1, uint32]
|
||||
Sha1Buffer = array[0 .. 80-1, uint32]
|
||||
|
||||
template clearBuffer(w: Sha1Buffer, len = 16) =
|
||||
zeroMem(addr(w), len * sizeof(uint32))
|
||||
|
||||
proc init(result: var Sha1State) =
|
||||
result[0] = 0x67452301'u32
|
||||
result[1] = 0xefcdab89'u32
|
||||
result[2] = 0x98badcfe'u32
|
||||
result[3] = 0x10325476'u32
|
||||
result[4] = 0xc3d2e1f0'u32
|
||||
|
||||
proc innerHash(state: var Sha1State, w: var Sha1Buffer) =
|
||||
var
|
||||
a = state[0]
|
||||
b = state[1]
|
||||
c = state[2]
|
||||
d = state[3]
|
||||
e = state[4]
|
||||
|
||||
var round = 0
|
||||
|
||||
template rot(value, bits: uint32): uint32 {.immediate.} =
|
||||
(value shl bits) or (value shr (32 - bits))
|
||||
|
||||
template sha1(fun, val: uint32): stmt =
|
||||
let t = rot(a, 5) + fun + e + val + w[round]
|
||||
e = d
|
||||
d = c
|
||||
c = rot(b, 30)
|
||||
b = a
|
||||
a = t
|
||||
|
||||
template process(body: stmt): stmt =
|
||||
w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1)
|
||||
body
|
||||
inc(round)
|
||||
|
||||
template wrap(dest, value: expr): stmt {.immediate.} =
|
||||
let v = dest + value
|
||||
dest = v
|
||||
|
||||
while round < 16:
|
||||
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
||||
inc(round)
|
||||
|
||||
while round < 20:
|
||||
process:
|
||||
sha1((b and c) or (not b and d), 0x5a827999'u32)
|
||||
|
||||
while round < 40:
|
||||
process:
|
||||
sha1(b xor c xor d, 0x6ed9eba1'u32)
|
||||
|
||||
while round < 60:
|
||||
process:
|
||||
sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32)
|
||||
|
||||
while round < 80:
|
||||
process:
|
||||
sha1(b xor c xor d, 0xca62c1d6'u32)
|
||||
|
||||
wrap state[0], a
|
||||
wrap state[1], b
|
||||
wrap state[2], c
|
||||
wrap state[3], d
|
||||
wrap state[4], e
|
||||
|
||||
template computeInternal(src: expr): stmt {.immediate.} =
|
||||
#Initialize state
|
||||
var state: Sha1State
|
||||
init(state)
|
||||
|
||||
#Create w buffer
|
||||
var w: Sha1Buffer
|
||||
|
||||
#Loop through all complete 64byte blocks.
|
||||
let byteLen = src.len
|
||||
let endOfFullBlocks = byteLen - 64
|
||||
var endCurrentBlock = 0
|
||||
var currentBlock = 0
|
||||
|
||||
while currentBlock <= endOfFullBlocks:
|
||||
endCurrentBlock = currentBlock + 64
|
||||
|
||||
var i = 0
|
||||
while currentBlock < endCurrentBlock:
|
||||
w[i] = uint32(src[currentBlock+3]) or
|
||||
uint32(src[currentBlock+2]) shl 8'u32 or
|
||||
uint32(src[currentBlock+1]) shl 16'u32 or
|
||||
uint32(src[currentBlock]) shl 24'u32
|
||||
currentBlock += 4
|
||||
inc(i)
|
||||
|
||||
innerHash(state, w)
|
||||
|
||||
#Handle last and not full 64 byte block if existing
|
||||
endCurrentBlock = byteLen - currentBlock
|
||||
clearBuffer(w)
|
||||
var lastBlockBytes = 0
|
||||
|
||||
while lastBlockBytes < endCurrentBlock:
|
||||
|
||||
var value = uint32(src[lastBlockBytes + currentBlock]) shl
|
||||
((3'u32 - (lastBlockBytes and 3)) shl 3)
|
||||
|
||||
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value
|
||||
inc(lastBlockBytes)
|
||||
|
||||
w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or (
|
||||
0x80'u32 shl ((3'u32 - (lastBlockBytes and 3)) shl 3)
|
||||
)
|
||||
|
||||
if endCurrentBlock >= 56:
|
||||
innerHash(state, w)
|
||||
clearBuffer(w)
|
||||
|
||||
w[15] = uint32(byteLen) shl 3
|
||||
innerHash(state, w)
|
||||
|
||||
# Store hash in result pointer, and make sure we get in in the correct order
|
||||
# on both endian models.
|
||||
for i in 0 .. Sha1DigestSize-1:
|
||||
result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255)
|
||||
|
||||
proc sha1(src: string) : Sha1Digest =
|
||||
## Calculate SHA1 from input string
|
||||
computeInternal(src)
|
||||
|
|
@ -209,7 +209,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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -310,16 +310,16 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
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 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,11 +335,11 @@ 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:
|
||||
of mModI:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(getInt(a) mod y, 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)
|
||||
|
|
|
|||
|
|
@ -207,9 +207,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 +218,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 +227,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):
|
||||
|
|
|
|||
|
|
@ -1268,6 +1268,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 =
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
import
|
||||
hashes, ast, astalgo, types
|
||||
|
||||
proc hashTree(n: PNode): THash =
|
||||
proc hashTree(n: PNode): Hash =
|
||||
if n == nil: return
|
||||
result = ord(n.kind)
|
||||
case n.kind
|
||||
|
|
@ -53,8 +53,8 @@ proc treesEquivalent(a, b: PNode): bool =
|
|||
result = true
|
||||
if result: result = sameTypeOrNil(a.typ, b.typ)
|
||||
|
||||
proc nodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int =
|
||||
var h: THash = k and high(t.data)
|
||||
proc nodeTableRawGet(t: TNodeTable, k: Hash, key: PNode): int =
|
||||
var h: Hash = k and high(t.data)
|
||||
while t.data[h].key != nil:
|
||||
if (t.data[h].h == k) and treesEquivalent(t.data[h].key, key):
|
||||
return h
|
||||
|
|
@ -66,9 +66,9 @@ proc nodeTableGet*(t: TNodeTable, key: PNode): int =
|
|||
if index >= 0: result = t.data[index].val
|
||||
else: result = low(int)
|
||||
|
||||
proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
|
||||
proc nodeTableRawInsert(data: var TNodePairSeq, k: Hash, key: PNode,
|
||||
val: int) =
|
||||
var h: THash = k and high(data)
|
||||
var h: Hash = k and high(data)
|
||||
while data[h].key != nil: h = nextTry(h, high(data))
|
||||
assert(data[h].key == nil)
|
||||
data[h].h = k
|
||||
|
|
@ -77,7 +77,7 @@ proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
|
|||
|
||||
proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
|
||||
var n: TNodePairSeq
|
||||
var k: THash = hashTree(key)
|
||||
var k: Hash = hashTree(key)
|
||||
var index = nodeTableRawGet(t, k, key)
|
||||
if index >= 0:
|
||||
assert(t.data[index].key != nil)
|
||||
|
|
@ -94,7 +94,7 @@ proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
|
|||
|
||||
proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int =
|
||||
var n: TNodePairSeq
|
||||
var k: THash = hashTree(key)
|
||||
var k: Hash = hashTree(key)
|
||||
var index = nodeTableRawGet(t, k, key)
|
||||
if index >= 0:
|
||||
assert(t.data[index].key != nil)
|
||||
|
|
|
|||
|
|
@ -682,11 +682,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcLtu:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
|
||||
of opcEqRef, opcEqNimrodNode:
|
||||
of opcEqRef:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
|
||||
regs[rc].node.kind == nkNilLit) or
|
||||
regs[rb].node == regs[rc].node)
|
||||
of opcEqNimrodNode:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal =
|
||||
ord(exprStructuralEquivalent(regs[rb].node, regs[rc].node))
|
||||
of opcXor:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
|
||||
|
|
|
|||
|
|
@ -710,9 +710,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABI(n, opcSubImmInt, dest, tmp, 1)
|
||||
c.freeTemp(tmp)
|
||||
of mPred, mSubI, mSubI64:
|
||||
of mPred, mSubI:
|
||||
c.genAddSubInt(n, dest, opcSubInt)
|
||||
of mSucc, mAddI, mAddI64:
|
||||
of mSucc, mAddI:
|
||||
c.genAddSubInt(n, dest, opcAddInt)
|
||||
of mInc, mDec:
|
||||
unused(n, dest)
|
||||
|
|
@ -759,28 +759,28 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||
c.freeTemp(d)
|
||||
c.freeTemp(tmp)
|
||||
of mCard: genCard(c, n, dest)
|
||||
of mMulI, mMulI64: genBinaryABCnarrow(c, n, dest, opcMulInt)
|
||||
of mDivI, mDivI64: genBinaryABCnarrow(c, n, dest, opcDivInt)
|
||||
of mModI, mModI64: genBinaryABCnarrow(c, n, dest, opcModInt)
|
||||
of mMulI: genBinaryABCnarrow(c, n, dest, opcMulInt)
|
||||
of mDivI: genBinaryABCnarrow(c, n, dest, opcDivInt)
|
||||
of mModI: genBinaryABCnarrow(c, n, dest, opcModInt)
|
||||
of mAddF64: genBinaryABC(c, n, dest, opcAddFloat)
|
||||
of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
|
||||
of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
|
||||
of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
|
||||
of mShrI, mShrI64: genBinaryABCnarrowU(c, n, dest, opcShrInt)
|
||||
of mShlI, mShlI64: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
||||
of mBitandI, mBitandI64: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||
of mBitorI, mBitorI64: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||
of mBitxorI, mBitxorI64: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
|
||||
of mShrI: genBinaryABCnarrowU(c, n, dest, opcShrInt)
|
||||
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
||||
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||
of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
|
||||
of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
|
||||
of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
|
||||
of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
|
||||
of mDivU: genBinaryABCnarrowU(c, n, dest, opcDivu)
|
||||
of mModU: genBinaryABCnarrowU(c, n, dest, opcModu)
|
||||
of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
|
||||
of mEqI, mEqB, mEqEnum, mEqCh:
|
||||
genBinaryABC(c, n, dest, opcEqInt)
|
||||
of mLeI, mLeI64, mLeEnum, mLeCh, mLeB:
|
||||
of mLeI, mLeEnum, mLeCh, mLeB:
|
||||
genBinaryABC(c, n, dest, opcLeInt)
|
||||
of mLtI, mLtI64, mLtEnum, mLtCh, mLtB:
|
||||
of mLtI, mLtEnum, mLtCh, mLtB:
|
||||
genBinaryABC(c, n, dest, opcLtInt)
|
||||
of mEqF64: genBinaryABC(c, n, dest, opcEqFloat)
|
||||
of mLeF64: genBinaryABC(c, n, dest, opcLeFloat)
|
||||
|
|
@ -796,7 +796,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||
genNarrow(c, n, dest)
|
||||
of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
|
||||
of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
|
||||
of mBitnotI, mBitnotI64:
|
||||
of mBitnotI:
|
||||
genUnaryABC(c, n, dest, opcBitnotInt)
|
||||
genNarrowU(c, n, dest)
|
||||
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
|
||||
|
|
@ -1013,7 +1013,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
|||
c.gABC(n, opcCallSite, dest)
|
||||
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
||||
of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
|
||||
mAbsI64, mDotDot:
|
||||
mDotDot:
|
||||
c.genCall(n, dest)
|
||||
of mExpandToAst:
|
||||
if n.len != 2:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ type
|
|||
wFloatchecks, wNanChecks, wInfChecks,
|
||||
wAssertions, wPatterns, wWarnings,
|
||||
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
|
||||
wDeadCodeElim, wSafecode, wNoForward,
|
||||
wDeadCodeElim, wSafecode, wNoForward, wNoRewrite,
|
||||
wPragma,
|
||||
wCompileTime, wNoInit,
|
||||
wPassc, wPassl, wBorrow, wDiscardable,
|
||||
|
|
@ -139,7 +139,7 @@ const
|
|||
|
||||
"assertions", "patterns", "warnings", "hints",
|
||||
"optimization", "raises", "writes", "reads", "size", "effects", "tags",
|
||||
"deadcodeelim", "safecode", "noforward",
|
||||
"deadcodeelim", "safecode", "noforward", "norewrite",
|
||||
"pragma",
|
||||
"compiletime", "noinit",
|
||||
"passc", "passl", "borrow", "discardable", "fieldchecks",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue