semfold compiles again

This commit is contained in:
Andreas Rumpf 2018-05-10 14:38:12 +02:00
commit a6e53ec47b
2 changed files with 267 additions and 265 deletions

View file

@ -217,11 +217,11 @@ errXExpectsTypeOrValue: "'$1' expects a type or value",
errXExpectsArrayType: "'$1' expects an array type", errXExpectsArrayType: "'$1' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context", errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: "division by zero", errConstantDivisionByZero: ,
errOrdinalTypeExpected: "ordinal type expected", errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: "over- or underflow", errOverOrUnderflow: ,
errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", errCannotEvalXBecauseIncompletelyDefined: ,
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
errDynlibRequiresExportc: "'dynlib' requires 'exportc'", errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
errUndeclaredFieldX: "undeclared field: '$1'", errUndeclaredFieldX: "undeclared field: '$1'",
@ -287,7 +287,7 @@ errImplOfXexpected: "implementation of '$1' expected",
errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
errDiscardValueX: "value of type '$1' has to be discarded", errDiscardValueX: "value of type '$1' has to be discarded",
errInvalidDiscard: "statement returns no value that can be discarded", errInvalidDiscard: "statement returns no value that can be discarded",
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", errIllegalConvFromXtoY: ,
errCannotBindXTwice: "cannot bind parameter '$1' twice", errCannotBindXTwice: "cannot bind parameter '$1' twice",
errInvalidOrderInArrayConstructor: "invalid order in array constructor", errInvalidOrderInArrayConstructor: "invalid order in array constructor",
errInvalidOrderInEnumX: "invalid order in enum '$1'", errInvalidOrderInEnumX: "invalid order in enum '$1'",

View file

@ -13,78 +13,16 @@
import import
strutils, options, ast, astalgo, trees, treetab, nimsets, times, strutils, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys, modulegraphs commands, magicsys, modulegraphs, strtabs
proc getConstExpr*(m: PSym, n: PNode): PNode proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
# evaluates the constant expression or returns nil if it is no constant
# expression
proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ):
result = true
proc foldAdd(a, b: BiggestInt, n: PNode): PNode =
let res = a +% b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n)
proc foldSub*(a, b: BiggestInt, n: PNode): PNode =
let res = a -% b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n)
proc foldAbs*(a: BiggestInt, n: PNode): PNode =
if a != firstOrd(n.typ):
result = newIntNodeT(a, n)
proc foldMod*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a mod b, n)
proc foldModU*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a %% b, n)
proc foldDiv*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
result = newIntNodeT(a div b, n)
proc foldDivU*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a /% b, n)
proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
let res = a *% b
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
let resAsFloat = toBiggestFloat(res)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd and checkInRange(n, res):
return newIntNodeT(res, n)
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res):
return newIntNodeT(res, n)
proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode =
case skipTypes(n.typ, abstractVarRange).kind case skipTypes(n.typ, abstractVarRange).kind
of tyInt: of tyInt:
result = newIntNode(nkIntLit, intVal) result = newIntNode(nkIntLit, intVal)
# See bug #6989. 'pred' et al only produce an int literal type if the # See bug #6989. 'pred' et al only produce an int literal type if the
# original type was 'int', not a distinct int etc. # original type was 'int', not a distinct int etc.
if n.typ.kind == tyInt: if n.typ.kind == tyInt:
result.typ = getIntLitType(result) result.typ = getIntLitType(g, result)
else: else:
result.typ = n.typ result.typ = n.typ
# hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
@ -97,20 +35,82 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode =
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode): PNode = proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
result = newFloatNode(nkFloatLit, floatVal) result = newFloatNode(nkFloatLit, floatVal)
if skipTypes(n.typ, abstractVarRange).kind == tyFloat: if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
result.typ = getFloatLitType(result) result.typ = getFloatLitType(g, result)
else: else:
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc newStrNodeT*(strVal: string, n: PNode): PNode = proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
result = newStrNode(nkStrLit, strVal) result = newStrNode(nkStrLit, strVal)
result.typ = n.typ result.typ = n.typ
result.info = n.info result.info = n.info
proc ordinalValToString*(a: PNode): string = proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
# evaluates the constant expression or returns nil if it is no constant
# expression
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ):
result = true
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a +% b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n, g)
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a -% b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n, g)
proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if a != firstOrd(n.typ):
result = newIntNodeT(a, n, g)
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a mod b, n, g)
proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a %% b, n, g)
proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
result = newIntNodeT(a div b, n, g)
proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a /% b, n, g)
proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a *% b
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
let resAsFloat = toBiggestFloat(res)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd and checkInRange(n, res):
return newIntNodeT(res, n, g)
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res):
return newIntNodeT(res, n, g)
proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
# ordinal # ordinal
var x = getInt(a) var x = getInt(a)
@ -122,14 +122,14 @@ proc ordinalValToString*(a: PNode): string =
of tyEnum: of tyEnum:
var n = t.n var n = t.n
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString") if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
var field = n.sons[i].sym var field = n.sons[i].sym
if field.position == x: if field.position == x:
if field.ast == nil: if field.ast == nil:
return field.name.s return field.name.s
else: else:
return field.ast.strVal return field.ast.strVal
internalError(a.info, "no symbol for ordinal value: " & $x) internalError(g.config, a.info, "no symbol for ordinal value: " & $x)
else: else:
result = $x result = $x
@ -148,12 +148,12 @@ proc pickIntRange(a, b: PType): PType =
proc isIntRangeOrLit(t: PType): bool = proc isIntRangeOrLit(t: PType): bool =
result = isIntRange(t) or isIntLit(t) result = isIntRange(t) or isIntLit(t)
proc makeRange(typ: PType, first, last: BiggestInt): PType = proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
let minA = min(first, last) let minA = min(first, last)
let maxA = max(first, last) let maxA = max(first, last)
let lowerNode = newIntNode(nkIntLit, minA) let lowerNode = newIntNode(nkIntLit, minA)
if typ.kind == tyInt and minA == maxA: if typ.kind == tyInt and minA == maxA:
result = getIntLitType(lowerNode) result = getIntLitType(g, lowerNode)
elif typ.kind in {tyUint, tyUInt64}: elif typ.kind in {tyUint, tyUInt64}:
# these are not ordinal types, so you get no subrange type for these: # these are not ordinal types, so you get no subrange type for these:
result = typ result = typ
@ -165,7 +165,7 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
result.n = n result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange})) addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType = proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
var n = newNode(nkRange) var n = newNode(nkRange)
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float))) addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float))) addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
@ -175,9 +175,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
proc evalIs(n, a: PNode): PNode = proc evalIs(n, a: PNode): PNode =
# XXX: This should use the standard isOpImpl # XXX: This should use the standard isOpImpl
internalAssert a.kind == nkSym and a.sym.kind == skType #internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and #internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType} # n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = a.sym.typ let t1 = a.sym.typ
@ -201,113 +201,113 @@ proc evalIs(n, a: PNode): PNode =
result = newIntNode(nkIntLit, ord(match)) result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ result.typ = n.typ
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
# b and c may be nil # b and c may be nil
result = nil result = nil
case m case m
of mOrd: result = newIntNodeT(getOrdValue(a), n) of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
of mChr: result = newIntNodeT(getInt(a), n) of mChr: result = newIntNodeT(getInt(a), n, g)
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n) of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n) of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
of mNot: result = newIntNodeT(1 - getInt(a), n) of mNot: result = newIntNodeT(1 - getInt(a), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n) of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g)
of mBitnotI: result = newIntNodeT(not getInt(a), n) of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit: if a.kind == nkNilLit:
result = newIntNodeT(0, n) result = newIntNodeT(0, n, g)
elif a.kind in {nkStrLit..nkTripleStrLit}: elif a.kind in {nkStrLit..nkTripleStrLit}:
result = newIntNodeT(len a.strVal, n) result = newIntNodeT(len a.strVal, n, g)
else: else:
result = newIntNodeT(sonsLen(a), n) # BUGFIX result = newIntNodeT(sonsLen(a), n, g)
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat: of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n) result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
# XXX: Hides overflow/underflow # XXX: Hides overflow/underflow
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n) of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n) of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
of mAbsI: result = foldAbs(getInt(a), n) of mAbsI: result = foldAbs(getInt(a), n, g)
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64 # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n) result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g)
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n) of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n) of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g)
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n) of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
of mPred: result = foldSub(getOrdValue(a), getInt(b), n) of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
of mAddI: result = foldAdd(getInt(a), getInt(b), n) of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
of mSubI: result = foldSub(getInt(a), getInt(b), n) of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
of mMulI: result = foldMul(getInt(a), getInt(b), n) of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
of mMinI: of mMinI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n) if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
else: result = newIntNodeT(getInt(a), n) else: result = newIntNodeT(getInt(a), n, g)
of mMaxI: of mMaxI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n) if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
else: result = newIntNodeT(getInt(b), n) else: result = newIntNodeT(getInt(b), n, g)
of mShlI: of mShlI:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n) of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n) of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n) of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
of tyInt64, tyInt, tyUInt..tyUInt64: of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n) result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
else: internalError(n.info, "constant folding for shl") else: internalError(g.config, n.info, "constant folding for shl")
of mShrI: of mShrI:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n) of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n) of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n) of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n, g)
of tyInt64, tyInt, tyUInt..tyUInt64: of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n) result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
else: internalError(n.info, "constant folding for shr") else: internalError(g.config, n.info, "constant folding for shr")
of mDivI: result = foldDiv(getInt(a), getInt(b), n) of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
of mModI: result = foldMod(getInt(a), getInt(b), n) of mModI: result = foldMod(getInt(a), getInt(b), n, g)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
of mDivF64: of mDivF64:
if getFloat(b) == 0.0: if getFloat(b) == 0.0:
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n) if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n) elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
else: result = newFloatNodeT(Inf, n) else: result = newFloatNodeT(Inf, n, g)
else: else:
result = newFloatNodeT(getFloat(a) / getFloat(b), n) result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
of mMaxF64: of mMaxF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n) if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
else: result = newFloatNodeT(getFloat(b), n) else: result = newFloatNodeT(getFloat(b), n, g)
of mMinF64: of mMinF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n) if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
else: result = newFloatNodeT(getFloat(a), n) else: result = newFloatNodeT(getFloat(a), n, g)
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n) of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
of mLtI, mLtB, mLtEnum, mLtCh: of mLtI, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)
of mLeI, mLeB, mLeEnum, mLeCh: of mLeI, mLeB, mLeEnum, mLeCh:
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n, g)
of mEqI, mEqB, mEqEnum, mEqCh: of mEqI, mEqB, mEqEnum, mEqCh:
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n, g)
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n) of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n, g)
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n) of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n, g)
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n) of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n, g)
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n) of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n, g)
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n) of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n) of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
of mLtU, mLtU64: of mLtU, mLtU64:
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
of mLeU, mLeU64: of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n) of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n) of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n) of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n) of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n) of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n) of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
of mModU: result = foldModU(getInt(a), getInt(b), n) of mModU: result = foldModU(getInt(a), getInt(b), n, g)
of mDivU: result = foldDivU(getInt(a), getInt(b), n) of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n) of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n) of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g)
of mLtSet: of mLtSet:
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n) result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g)
of mMulSet: of mMulSet:
result = nimsets.intersectSets(a, b) result = nimsets.intersectSets(a, b)
result.info = n.info result.info = n.info
@ -320,57 +320,57 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mSymDiffSet: of mSymDiffSet:
result = nimsets.symdiffSets(a, b) result = nimsets.symdiffSets(a, b)
result.info = n.info result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n) of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n) of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
of mRepr: of mRepr:
# BUGFIX: we cannot eval mRepr here for reasons that I forgot. # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
discard discard
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
of mBoolToStr: of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n) if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
else: result = newStrNodeT("true", n) else: result = newStrNodeT("true", n, g)
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n) of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
of mCopyStrLast: of mCopyStrLast:
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
int(getOrdValue(c))), n) int(getOrdValue(c))), n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n) of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr: of mCStrToStr, mCharToStr:
if a.kind == nkBracket: if a.kind == nkBracket:
var s = "" var s = ""
for b in a.sons: for b in a.sons:
s.add b.getStrOrChar s.add b.getStrOrChar
result = newStrNodeT(s, n) result = newStrNodeT(s, n, g)
else: else:
result = newStrNodeT(getStrOrChar(a), n) result = newStrNodeT(getStrOrChar(a), n, g)
of mStrToStr: result = a of mStrToStr: result = a
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
of mArrToSeq: of mArrToSeq:
result = copyTree(a) result = copyTree(a)
result.typ = n.typ result.typ = n.typ
of mCompileOption: of mCompileOption:
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n) result = newIntNodeT(ord(commands.testCompileOption(g.config, a.getStr, n.info)), n, g)
of mCompileOptionArg: of mCompileOptionArg:
result = newIntNodeT(ord( result = newIntNodeT(ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n) testCompileOptionArg(g.config, getStr(a), getStr(b), n.info)), n, g)
of mEqProc: of mEqProc:
result = newIntNodeT(ord( result = newIntNodeT(ord(
exprStructuralEquivalent(a, b, strictSymEquality=true)), n) exprStructuralEquivalent(a, b, strictSymEquality=true)), n, g)
else: discard else: discard
proc getConstIfExpr(c: PSym, n: PNode): PNode = proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
result = nil result = nil
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it.len == 2: if it.len == 2:
var e = getConstExpr(c, it.sons[0]) var e = getConstExpr(c, it.sons[0], g)
if e == nil: return nil if e == nil: return nil
if getOrdValue(e) != 0: if getOrdValue(e) != 0:
if result == nil: if result == nil:
result = getConstExpr(c, it.sons[1]) result = getConstExpr(c, it.sons[1], g)
if result == nil: return if result == nil: return
elif it.len == 1: elif it.len == 1:
if result == nil: result = getConstExpr(c, it.sons[0]) if result == nil: result = getConstExpr(c, it.sons[0], g)
else: internalError(it.info, "getConstIfExpr()") else: internalError(g.config, it.info, "getConstIfExpr()")
proc leValueConv*(a, b: PNode): bool = proc leValueConv*(a, b: PNode): bool =
result = false result = false
@ -379,66 +379,66 @@ proc leValueConv*(a, b: PNode): bool =
case b.kind case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
else: internalError(a.info, "leValueConv") else: result = false #internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
case b.kind case b.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal)) of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: internalError(a.info, "leValueConv") else: result = false # internalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv") else: result = false # internalError(a.info, "leValueConv")
proc magicCall(m: PSym, n: PNode): PNode = proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
if sonsLen(n) <= 1: return if sonsLen(n) <= 1: return
var s = n.sons[0].sym var s = n.sons[0].sym
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1], g)
var b, c: PNode var b, c: PNode
if a == nil: return if a == nil: return
if sonsLen(n) > 2: if sonsLen(n) > 2:
b = getConstExpr(m, n.sons[2]) b = getConstExpr(m, n.sons[2], g)
if b == nil: return if b == nil: return
if sonsLen(n) > 3: if sonsLen(n) > 3:
c = getConstExpr(m, n.sons[3]) c = getConstExpr(m, n.sons[3], g)
if c == nil: return if c == nil: return
result = evalOp(s.magic, n, a, b, c) result = evalOp(s.magic, n, a, b, c, g)
proc getAppType(n: PNode): PNode = proc getAppType(n: PNode; g: ModuleGraph): PNode =
if gGlobalOptions.contains(optGenDynLib): if gGlobalOptions.contains(optGenDynLib):
result = newStrNodeT("lib", n) result = newStrNodeT("lib", n, g)
elif gGlobalOptions.contains(optGenStaticLib): elif gGlobalOptions.contains(optGenStaticLib):
result = newStrNodeT("staticlib", n) result = newStrNodeT("staticlib", n, g)
elif gGlobalOptions.contains(optGenGuiApp): elif gGlobalOptions.contains(optGenGuiApp):
result = newStrNodeT("gui", n) result = newStrNodeT("gui", n, g)
else: else:
result = newStrNodeT("console", n) result = newStrNodeT("console", n, g)
proc rangeCheck(n: PNode, value: BiggestInt) = proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
var err = false var err = false
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}: if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true) err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true)
else: else:
err = value < firstOrd(n.typ) or value > lastOrd(n.typ) err = value < firstOrd(n.typ) or value > lastOrd(n.typ)
if err: if err:
localError(n.info, errGenerated, "cannot convert " & $value & localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ)) " to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode = proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode =
# XXX range checks? # XXX range checks?
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64, tyUInt..tyUInt64: of tyInt..tyInt64, tyUInt..tyUInt64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n) result = newIntNodeT(int(getFloat(a)), n, g)
of tyChar: result = newIntNodeT(getOrdValue(a), n) of tyChar: result = newIntNodeT(getOrdValue(a), n, g)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit}: if check and result.kind in {nkCharLit..nkUInt64Lit}:
rangeCheck(n, result.intVal) rangeCheck(n, result.intVal, g)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n) result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
@ -448,19 +448,19 @@ proc foldConv*(n, a: PNode; check = false): PNode =
result = a result = a
result.typ = n.typ result.typ = n.typ
proc getArrayConstr(m: PSym, n: PNode): PNode = proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode =
if n.kind == nkBracket: if n.kind == nkBracket:
result = n result = n
else: else:
result = getConstExpr(m, n) result = getConstExpr(m, n, g)
if result == nil: result = n if result == nil: result = n
proc foldArrayAccess(m: PSym, n: PNode): PNode = proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
var x = getConstExpr(m, n.sons[0]) var x = getConstExpr(m, n.sons[0], g)
if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc: if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
return return
var y = getConstExpr(m, n.sons[1]) var y = getConstExpr(m, n.sons[1], g)
if y == nil: return if y == nil: return
var idx = getOrdValue(y) var idx = getOrdValue(y)
@ -470,24 +470,24 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
result = x.sons[int(idx)] result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
else: else:
localError(n.info, errIndexOutOfBounds) localError(g.config, n.info, "index out of bounds: " & $n)
of nkBracket: of nkBracket:
idx = idx - x.typ.firstOrd idx = idx - x.typ.firstOrd
if idx >= 0 and idx < x.len: result = x.sons[int(idx)] if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
else: localError(n.info, errIndexOutOfBounds) else: localError(g.config, n.info, "index out of bounds: " & $n)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ) result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < len(x.strVal): if idx >= 0 and idx < len(x.strVal):
result.intVal = ord(x.strVal[int(idx)]) result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal): elif idx == len(x.strVal) and optLaxStrings in gOptions:
discard discard
else: else:
localError(n.info, errIndexOutOfBounds) localError(g.config, n.info, "index out of bounds: " & $n)
else: discard else: discard
proc foldFieldAccess(m: PSym, n: PNode): PNode = proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
# a real field access; proc calls have already been transformed # a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0]) var x = getConstExpr(m, n.sons[0], g)
if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
var field = n.sons[1].sym var field = n.sons[1].sym
@ -501,13 +501,13 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
if it.sons[0].sym.name.id == field.name.id: if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1] result = x.sons[i].sons[1]
return return
localError(n.info, errFieldXNotFound, field.name.s) localError(g.config, n.info, "field not found: " & field.name.s)
proc foldConStrStr(m: PSym, n: PNode): PNode = proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = newNodeIT(nkStrLit, n.info, n.typ) result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = "" result.strVal = ""
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let a = getConstExpr(m, n.sons[i]) let a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil if a == nil: return nil
result.strVal.add(getStrOrChar(a)) result.strVal.add(getStrOrChar(a))
@ -519,7 +519,7 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
else: else:
result.typ = s.typ result.typ = s.typ
proc getConstExpr(m: PSym, n: PNode): PNode = proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = nil result = nil
proc getSrcTimestamp(): DateTime = proc getSrcTimestamp(): DateTime =
@ -539,32 +539,35 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
var s = n.sym var s = n.sym
case s.kind case s.kind
of skEnumField: of skEnumField:
result = newIntNodeT(s.position, n) result = newIntNodeT(s.position, n, g)
of skConst: of skConst:
case s.magic case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g)
of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(), of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
"yyyy-MM-dd"), n) "yyyy-MM-dd"), n, g)
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(), of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
"HH:mm:ss"), n) "HH:mm:ss"), n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n) of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n) of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n) of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g)
of mAppType: result = getAppType(n) of mAppType: result = getAppType(n, g)
of mNaN: result = newFloatNodeT(NaN, n) of mNaN: result = newFloatNodeT(NaN, n, g)
of mInf: result = newFloatNodeT(Inf, n) of mInf: result = newFloatNodeT(Inf, n, g)
of mNegInf: result = newFloatNodeT(NegInf, n) of mNegInf: result = newFloatNodeT(NegInf, n, g)
of mIntDefine: of mIntDefine:
if isDefined(s.name): if isDefined(g.config, s.name.s):
result = newIntNodeT(lookupSymbol(s.name).parseInt, n) try:
result = newIntNodeT(g.config.symbols[s.name.s].parseInt, n, g)
except ValueError:
localError(g.config, n.info, "expression is not an integer literal")
of mStrDefine: of mStrDefine:
if isDefined(s.name): if isDefined(g.config, s.name.s):
result = newStrNodeT(lookupSymbol(s.name), n) result = newStrNodeT(g.config.symbols[s.name.s], n, g)
else: else:
result = copyTree(s.ast) result = copyTree(s.ast)
of {skProc, skFunc, skMethod}: of skProc, skFunc, skMethod:
result = n result = n
of skType: of skType:
# XXX gensym'ed symbols can come here and cannot be resolved. This is # XXX gensym'ed symbols can come here and cannot be resolved. This is
@ -584,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkCharLit..nkNilLit: of nkCharLit..nkNilLit:
result = copyNode(n) result = copyNode(n)
of nkIfExpr: of nkIfExpr:
result = getConstIfExpr(m, n) result = getConstIfExpr(m, n, g)
of nkCallKinds: of nkCallKinds:
if n.sons[0].kind != nkSym: return if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym var s = n.sons[0].sym
@ -597,68 +600,67 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mSizeOf: of mSizeOf:
var a = n.sons[1] var a = n.sons[1]
if computeSize(a.typ) < 0: if computeSize(a.typ) < 0:
localError(a.info, errCannotEvalXBecauseIncompletelyDefined, localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
"sizeof")
result = nil result = nil
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
IntegralTypes+NilableTypes+{tySet}: IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}: #{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n) result = newIntNodeT(getSize(a.typ), n, g)
else: else:
result = nil result = nil
# XXX: size computation for complex types is still wrong # XXX: size computation for complex types is still wrong
of mLow: of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n) result = newIntNodeT(firstOrd(n.sons[1].typ), n, g)
of mHigh: of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g)
else: else:
var a = getArrayConstr(m, n.sons[1]) var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away: # we can optimize it away:
result = newIntNodeT(sonsLen(a)-1, n) result = newIntNodeT(sonsLen(a)-1, n, g)
of mLengthOpenArray: of mLengthOpenArray:
var a = getArrayConstr(m, n.sons[1]) var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away! This fixes the bug ``len(134)``. # we can optimize it away! This fixes the bug ``len(134)``.
result = newIntNodeT(sonsLen(a), n) result = newIntNodeT(sonsLen(a), n, g)
else: else:
result = magicCall(m, n) result = magicCall(m, n, g)
of mLengthArray: of mLengthArray:
# It doesn't matter if the argument is const or not for mLengthArray. # It doesn't matter if the argument is const or not for mLengthArray.
# This fixes bug #544. # This fixes bug #544.
result = newIntNodeT(lengthOrd(n.sons[1].typ), n) result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g)
of mAstToStr: of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
of mConStrStr: of mConStrStr:
result = foldConStrStr(m, n) result = foldConStrStr(m, n, g)
of mIs: of mIs:
let a = getConstExpr(m, n[1]) let a = getConstExpr(m, n[1], g)
if a != nil and a.kind == nkSym and a.sym.kind == skType: if a != nil and a.kind == nkSym and a.sym.kind == skType:
result = evalIs(n, a) result = evalIs(n, a)
else: else:
result = magicCall(m, n) result = magicCall(m, n, g)
except OverflowError: except OverflowError:
localError(n.info, errOverOrUnderflow) localError(g.config, n.info, "over- or underflow")
except DivByZeroError: except DivByZeroError:
localError(n.info, errConstantDivisionByZero) localError(g.config, n.info, "division by zero")
of nkAddr: of nkAddr:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0], g)
if a != nil: if a != nil:
result = n result = n
n.sons[0] = a n.sons[0] = a
of nkBracket: of nkBracket:
result = copyTree(n) result = copyTree(n)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
of nkRange: of nkRange:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0], g)
if a == nil: return if a == nil: return
var b = getConstExpr(m, n.sons[1]) var b = getConstExpr(m, n.sons[1], g)
if b == nil: return if b == nil: return
result = copyNode(n) result = copyNode(n)
addSon(result, a) addSon(result, a)
@ -666,7 +668,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkCurly: of nkCurly:
result = copyTree(n) result = copyTree(n)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
@ -682,45 +684,45 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = copyTree(n) result = copyTree(n)
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i].sons[1]) var a = getConstExpr(m, n.sons[i].sons[1], g)
if a == nil: return nil if a == nil: return nil
result.sons[i].sons[1] = a result.sons[i].sons[1] = a
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i]) var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil if a == nil: return nil
result.sons[i] = a result.sons[i] = a
incl(result.flags, nfAllConst) incl(result.flags, nfAllConst)
of nkChckRangeF, nkChckRange64, nkChckRange: of nkChckRangeF, nkChckRange64, nkChckRange:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0], g)
if a == nil: return if a == nil: return
if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
result = a # a <= x and x <= b result = a # a <= x and x <= b
result.typ = n.typ result.typ = n.typ
else: else:
localError(n.info, errGenerated, `%`( localError(g.config, n.info,
msgKindToString(errIllegalConvFromXtoY), "conversion from $1 to $2 is invalid" %
[typeToString(n.sons[0].typ), typeToString(n.typ)])) [typeToString(n.sons[0].typ), typeToString(n.typ)])
of nkStringToCString, nkCStringToString: of nkStringToCString, nkCStringToString:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0], g)
if a == nil: return if a == nil: return
result = a result = a
result.typ = n.typ result.typ = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return
result = foldConv(n, a, check=n.kind == nkHiddenStdConv) result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
of nkCast: of nkCast:
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return
if n.typ != nil and n.typ.kind in NilableTypes: if n.typ != nil and n.typ.kind in NilableTypes:
# we allow compile-time 'cast' for pointer types: # we allow compile-time 'cast' for pointer types:
result = a result = a
result.typ = n.typ result.typ = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n) of nkBracketExpr: result = foldArrayAccess(m, n, g)
of nkDotExpr: result = foldFieldAccess(m, n) of nkDotExpr: result = foldFieldAccess(m, n, g)
of nkStmtListExpr: of nkStmtListExpr:
if n.len == 2 and n[0].kind == nkComesFrom: if n.len == 2 and n[0].kind == nkComesFrom:
result = getConstExpr(m, n[1]) result = getConstExpr(m, n[1], g)
else: else:
discard discard