1#
2#
3#           The Nim Compiler
4#        (c) Copyright 2015 Andreas Rumpf
5#
6#    See the file "copying.txt", included in this
7#    distribution, for details about the copyright.
8#
9
10# this module folds constants; used by semantic checking phase
11# and evaluation phase
12
13import
14  strutils, options, ast, trees, nimsets,
15  platform, math, msgs, idents, renderer, types,
16  commands, magicsys, modulegraphs, strtabs, lineinfos
17
18from system/memory import nimCStrLen
19
20proc errorType*(g: ModuleGraph): PType =
21  ## creates a type representing an error state
22  result = newType(tyError, nextTypeId(g.idgen), g.owners[^1])
23  result.flags.incl tfCheckedForDestructor
24
25proc getIntLitTypeG(g: ModuleGraph; literal: PNode; idgen: IdGenerator): PType =
26  # we cache some common integer literal types for performance:
27  let ti = getSysType(g, literal.info, tyInt)
28  result = copyType(ti, nextTypeId(idgen), ti.owner)
29  result.n = literal
30
31proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
32  result = newIntTypeNode(intVal, n.typ)
33  # See bug #6989. 'pred' et al only produce an int literal type if the
34  # original type was 'int', not a distinct int etc.
35  if n.typ.kind == tyInt:
36    # access cache for the int lit type
37    result.typ = getIntLitTypeG(g, result, idgen)
38  result.info = n.info
39
40proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
41  if n.typ.skipTypes(abstractInst).kind == tyFloat32:
42    result = newFloatNode(nkFloat32Lit, floatVal)
43  else:
44    result = newFloatNode(nkFloatLit, floatVal)
45  result.typ = n.typ
46  result.info = n.info
47
48proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
49  result = newStrNode(nkStrLit, strVal)
50  result.typ = n.typ
51  result.info = n.info
52
53proc getConstExpr*(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
54  # evaluates the constant expression or returns nil if it is no constant
55  # expression
56proc evalOp*(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
57
58proc checkInRange(conf: ConfigRef; n: PNode, res: Int128): bool =
59  res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ)
60
61proc foldAdd(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
62  let res = a + b
63  if checkInRange(g.config, n, res):
64    result = newIntNodeT(res, n, idgen, g)
65
66proc foldSub(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
67  let res = a - b
68  if checkInRange(g.config, n, res):
69    result = newIntNodeT(res, n, idgen, g)
70
71proc foldUnarySub(a: Int128, n: PNode; idgen: IdGenerator, g: ModuleGraph): PNode =
72  if a != firstOrd(g.config, n.typ):
73    result = newIntNodeT(-a, n, idgen, g)
74
75proc foldAbs(a: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
76  if a != firstOrd(g.config, n.typ):
77    result = newIntNodeT(abs(a), n, idgen, g)
78
79proc foldMul(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
80  let res = a * b
81  if checkInRange(g.config, n, res):
82    return newIntNodeT(res, n, idgen, g)
83
84proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
85  # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
86  # ordinal
87  var x = getInt(a)
88
89  var t = skipTypes(a.typ, abstractRange)
90  case t.kind
91  of tyChar:
92    result = $chr(toInt64(x) and 0xff)
93  of tyEnum:
94    var n = t.n
95    for i in 0..<n.len:
96      if n[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
97      var field = n[i].sym
98      if field.position == x:
99        if field.ast == nil:
100          return field.name.s
101        else:
102          return field.ast.strVal
103    localError(g.config, a.info,
104      "Cannot convert int literal to $1. The value is invalid." %
105        [typeToString(t)])
106  else:
107    result = $x
108
109proc isFloatRange(t: PType): bool {.inline.} =
110  result = t.kind == tyRange and t[0].kind in {tyFloat..tyFloat128}
111
112proc isIntRange(t: PType): bool {.inline.} =
113  result = t.kind == tyRange and t[0].kind in {
114      tyInt..tyInt64, tyUInt8..tyUInt32}
115
116proc pickIntRange(a, b: PType): PType =
117  if isIntRange(a): result = a
118  elif isIntRange(b): result = b
119  else: result = a
120
121proc isIntRangeOrLit(t: PType): bool =
122  result = isIntRange(t) or isIntLit(t)
123
124proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
125  # b and c may be nil
126  result = nil
127  case m
128  of mOrd: result = newIntNodeT(getOrdValue(a), n, idgen, g)
129  of mChr: result = newIntNodeT(getInt(a), n, idgen, g)
130  of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, idgen, g)
131  of mUnaryMinusF64: result = newFloatNodeT(-getFloat(a), n, g)
132  of mNot: result = newIntNodeT(One - getInt(a), n, idgen, g)
133  of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
134  of mBitnotI:
135    if n.typ.isUnsigned:
136      result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, idgen, g)
137    else:
138      result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
139  of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
140  of mLengthSeq, mLengthOpenArray, mLengthStr:
141    if a.kind == nkNilLit:
142      result = newIntNodeT(Zero, n, idgen, g)
143    elif a.kind in {nkStrLit..nkTripleStrLit}:
144      if a.typ.kind == tyString:
145        result = newIntNodeT(toInt128(a.strVal.len), n, idgen, g)
146      elif a.typ.kind == tyCstring:
147        result = newIntNodeT(toInt128(nimCStrLen(a.strVal.cstring)), n, idgen, g)
148    else:
149      result = newIntNodeT(toInt128(a.len), n, idgen, g)
150  of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
151  # XXX: Hides overflow/underflow
152  of mAbsI: result = foldAbs(getInt(a), n, idgen, g)
153  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, idgen, g)
154  of mPred: result = foldSub(getOrdValue(a), getInt(b), n, idgen, g)
155  of mAddI: result = foldAdd(getInt(a), getInt(b), n, idgen, g)
156  of mSubI: result = foldSub(getInt(a), getInt(b), n, idgen, g)
157  of mMulI: result = foldMul(getInt(a), getInt(b), n, idgen, g)
158  of mMinI:
159    let argA = getInt(a)
160    let argB = getInt(b)
161    result = newIntNodeT(if argA < argB: argA else: argB, n, idgen, g)
162  of mMaxI:
163    let argA = getInt(a)
164    let argB = getInt(b)
165    result = newIntNodeT(if argA > argB: argA else: argB, n, idgen, g)
166  of mShlI:
167    case skipTypes(n.typ, abstractRange).kind
168    of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
169    of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
170    of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
171    of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
172    of tyInt:
173      if g.config.target.intSize == 4:
174        result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
175      else:
176        result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
177    of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
178    of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
179    of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
180    of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
181    of tyUInt:
182      if g.config.target.intSize == 4:
183        result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
184      else:
185        result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
186    else: internalError(g.config, n.info, "constant folding for shl")
187  of mShrI:
188    var a = cast[uint64](getInt(a))
189    let b = cast[uint64](getInt(b))
190    # To support the ``-d:nimOldShiftRight`` flag, we need to mask the
191    # signed integers to cut off the extended sign bit in the internal
192    # representation.
193    if 0'u64 < b: # do not cut off the sign extension, when there is
194              # no bit shifting happening.
195      case skipTypes(n.typ, abstractRange).kind
196      of tyInt8: a = a and 0xff'u64
197      of tyInt16: a = a and 0xffff'u64
198      of tyInt32: a = a and 0xffffffff'u64
199      of tyInt:
200        if g.config.target.intSize == 4:
201          a = a and 0xffffffff'u64
202      else:
203        # unsigned and 64 bit integers don't need masking
204        discard
205    let c = cast[BiggestInt](a shr b)
206    result = newIntNodeT(toInt128(c), n, idgen, g)
207  of mAshrI:
208    case skipTypes(n.typ, abstractRange).kind
209    of tyInt8: result =  newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, idgen, g)
210    of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, idgen, g)
211    of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, idgen, g)
212    of tyInt64, tyInt:
213      result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, idgen, g)
214    else: internalError(g.config, n.info, "constant folding for ashr")
215  of mDivI:
216    let argA = getInt(a)
217    let argB = getInt(b)
218    if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
219      result = newIntNodeT(argA div argB, n, idgen, g)
220  of mModI:
221    let argA = getInt(a)
222    let argB = getInt(b)
223    if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
224      result = newIntNodeT(argA mod argB, n, idgen, g)
225  of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
226  of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
227  of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
228  of mDivF64:
229    result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
230  of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, idgen, g)
231  of mLtI, mLtB, mLtEnum, mLtCh:
232    result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, idgen, g)
233  of mLeI, mLeB, mLeEnum, mLeCh:
234    result = newIntNodeT(toInt128(ord(getOrdValue(a) <= getOrdValue(b))), n, idgen, g)
235  of mEqI, mEqB, mEqEnum, mEqCh:
236    result = newIntNodeT(toInt128(ord(getOrdValue(a) == getOrdValue(b))), n, idgen, g)
237  of mLtF64: result = newIntNodeT(toInt128(ord(getFloat(a) < getFloat(b))), n, idgen, g)
238  of mLeF64: result = newIntNodeT(toInt128(ord(getFloat(a) <= getFloat(b))), n, idgen, g)
239  of mEqF64: result = newIntNodeT(toInt128(ord(getFloat(a) == getFloat(b))), n, idgen, g)
240  of mLtStr: result = newIntNodeT(toInt128(ord(getStr(a) < getStr(b))), n, idgen, g)
241  of mLeStr: result = newIntNodeT(toInt128(ord(getStr(a) <= getStr(b))), n, idgen, g)
242  of mEqStr: result = newIntNodeT(toInt128(ord(getStr(a) == getStr(b))), n, idgen, g)
243  of mLtU:
244    result = newIntNodeT(toInt128(ord(`<%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g)
245  of mLeU:
246    result = newIntNodeT(toInt128(ord(`<=%`(toInt64(getOrdValue(a)), toInt64(getOrdValue(b))))), n, idgen, g)
247  of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, idgen, g)
248  of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
249  of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
250  of mAddU:
251    let val = maskBytes(getInt(a) + getInt(b), int(getSize(g.config, n.typ)))
252    result = newIntNodeT(val, n, idgen, g)
253  of mSubU:
254    let val = maskBytes(getInt(a) - getInt(b), int(getSize(g.config, n.typ)))
255    result = newIntNodeT(val, n, idgen, g)
256    # echo "subU: ", val, " n: ", n, " result: ", val
257  of mMulU:
258    let val = maskBytes(getInt(a) * getInt(b), int(getSize(g.config, n.typ)))
259    result = newIntNodeT(val, n, idgen, g)
260  of mModU:
261    let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
262    let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
263    if argB != Zero:
264      result = newIntNodeT(argA mod argB, n, idgen, g)
265  of mDivU:
266    let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
267    let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
268    if argB != Zero:
269      result = newIntNodeT(argA div argB, n, idgen, g)
270  of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)
271  of mEqSet: result = newIntNodeT(toInt128(ord(equalSets(g.config, a, b))), n, idgen, g)
272  of mLtSet:
273    result = newIntNodeT(toInt128(ord(
274      containsSets(g.config, a, b) and not equalSets(g.config, a, b))), n, idgen, g)
275  of mMulSet:
276    result = nimsets.intersectSets(g.config, a, b)
277    result.info = n.info
278  of mPlusSet:
279    result = nimsets.unionSets(g.config, a, b)
280    result.info = n.info
281  of mMinusSet:
282    result = nimsets.diffSets(g.config, a, b)
283    result.info = n.info
284  of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
285  of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, idgen, g)
286  of mRepr:
287    # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
288    discard
289  of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
290  of mBoolToStr:
291    if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
292    else: result = newStrNodeT("true", n, g)
293  of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
294  of mCStrToStr, mCharToStr:
295    if a.kind == nkBracket:
296      var s = ""
297      for b in a.sons:
298        s.add b.getStrOrChar
299      result = newStrNodeT(s, n, g)
300    else:
301      result = newStrNodeT(getStrOrChar(a), n, g)
302  of mStrToStr: result = newStrNodeT(getStrOrChar(a), n, g)
303  of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
304  of mArrToSeq:
305    result = copyTree(a)
306    result.typ = n.typ
307  of mCompileOption:
308    result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g)
309  of mCompileOptionArg:
310    result = newIntNodeT(toInt128(ord(
311      testCompileOptionArg(g.config, getStr(a), getStr(b), n.info))), n, idgen, g)
312  of mEqProc:
313    result = newIntNodeT(toInt128(ord(
314        exprStructuralEquivalent(a, b, strictSymEquality=true))), n, idgen, g)
315  else: discard
316
317proc getConstIfExpr(c: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
318  result = nil
319  for i in 0..<n.len:
320    var it = n[i]
321    if it.len == 2:
322      var e = getConstExpr(c, it[0], idgen, g)
323      if e == nil: return nil
324      if getOrdValue(e) != 0:
325        if result == nil:
326          result = getConstExpr(c, it[1], idgen, g)
327          if result == nil: return
328    elif it.len == 1:
329      if result == nil: result = getConstExpr(c, it[0], idgen, g)
330    else: internalError(g.config, it.info, "getConstIfExpr()")
331
332proc leValueConv*(a, b: PNode): bool =
333  result = false
334  case a.kind
335  of nkCharLit..nkUInt64Lit:
336    case b.kind
337    of nkCharLit..nkUInt64Lit: result = a.getInt <= b.getInt
338    of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
339    else: result = false #internalError(a.info, "leValueConv")
340  of nkFloatLit..nkFloat128Lit:
341    case b.kind
342    of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
343    of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat64(b.getInt)
344    else: result = false # internalError(a.info, "leValueConv")
345  else: result = false # internalError(a.info, "leValueConv")
346
347proc magicCall(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
348  if n.len <= 1: return
349
350  var s = n[0].sym
351  var a = getConstExpr(m, n[1], idgen, g)
352  var b, c: PNode
353  if a == nil: return
354  if n.len > 2:
355    b = getConstExpr(m, n[2], idgen, g)
356    if b == nil: return
357    if n.len > 3:
358      c = getConstExpr(m, n[3], idgen, g)
359      if c == nil: return
360  result = evalOp(s.magic, n, a, b, c, idgen, g)
361
362proc getAppType(n: PNode; g: ModuleGraph): PNode =
363  if g.config.globalOptions.contains(optGenDynLib):
364    result = newStrNodeT("lib", n, g)
365  elif g.config.globalOptions.contains(optGenStaticLib):
366    result = newStrNodeT("staticlib", n, g)
367  elif g.config.globalOptions.contains(optGenGuiApp):
368    result = newStrNodeT("gui", n, g)
369  else:
370    result = newStrNodeT("console", n, g)
371
372proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
373  if value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ):
374    localError(g.config, n.info, "cannot convert " & $value &
375                                    " to " & typeToString(n.typ))
376
377proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): PNode =
378  let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
379  let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})
380
381  # if srcTyp.kind == tyUInt64 and "FFFFFF" in $n:
382  #   echo "n: ", n, " a: ", a
383  #   echo "from: ", srcTyp, " to: ", dstTyp, " check: ", check
384  #   echo getInt(a)
385  #   echo high(int64)
386  #   writeStackTrace()
387  case dstTyp.kind
388  of tyBool:
389    case srcTyp.kind
390    of tyFloat..tyFloat64:
391      result = newIntNodeT(toInt128(getFloat(a) != 0.0), n, idgen, g)
392    of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
393      result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g)
394    of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`?
395      result = a
396      result.typ = n.typ
397    else: doAssert false, $srcTyp.kind
398  of tyInt..tyInt64, tyUInt..tyUInt64:
399    case srcTyp.kind
400    of tyFloat..tyFloat64:
401      result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g)
402    of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
403      var val = a.getOrdValue
404      if check: rangeCheck(n, val, g)
405      result = newIntNodeT(val, n, idgen, g)
406      if dstTyp.kind in {tyUInt..tyUInt64}:
407        result.transitionIntKind(nkUIntLit)
408    else:
409      result = a
410      result.typ = n.typ
411    if check and result.kind in {nkCharLit..nkUInt64Lit}:
412      rangeCheck(n, getInt(result), g)
413  of tyFloat..tyFloat64:
414    case srcTyp.kind
415    of tyInt..tyInt64, tyEnum, tyBool, tyChar:
416      result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
417    else:
418      result = a
419      result.typ = n.typ
420  of tyOpenArray, tyVarargs, tyProc, tyPointer:
421    discard
422  else:
423    result = a
424    result.typ = n.typ
425
426proc getArrayConstr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
427  if n.kind == nkBracket:
428    result = n
429  else:
430    result = getConstExpr(m, n, idgen, g)
431    if result == nil: result = n
432
433proc foldArrayAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
434  var x = getConstExpr(m, n[0], idgen, g)
435  if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
436    return
437
438  var y = getConstExpr(m, n[1], idgen, g)
439  if y == nil: return
440
441  var idx = toInt64(getOrdValue(y))
442  case x.kind
443  of nkPar, nkTupleConstr:
444    if idx >= 0 and idx < x.len:
445      result = x.sons[idx]
446      if result.kind == nkExprColonExpr: result = result[1]
447    else:
448      localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
449  of nkBracket:
450    idx -= toInt64(firstOrd(g.config, x.typ))
451    if idx >= 0 and idx < x.len: result = x[int(idx)]
452    else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
453  of nkStrLit..nkTripleStrLit:
454    result = newNodeIT(nkCharLit, x.info, n.typ)
455    if idx >= 0 and idx < x.strVal.len:
456      result.intVal = ord(x.strVal[int(idx)])
457    else:
458      localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n)
459  else: discard
460
461proc foldFieldAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
462  # a real field access; proc calls have already been transformed
463  var x = getConstExpr(m, n[0], idgen, g)
464  if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
465
466  var field = n[1].sym
467  for i in ord(x.kind == nkObjConstr)..<x.len:
468    var it = x[i]
469    if it.kind != nkExprColonExpr:
470      # lookup per index:
471      result = x[field.position]
472      if result.kind == nkExprColonExpr: result = result[1]
473      return
474    if it[0].sym.name.id == field.name.id:
475      result = x[i][1]
476      return
477  localError(g.config, n.info, "field not found: " & field.name.s)
478
479proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
480  result = newNodeIT(nkStrLit, n.info, n.typ)
481  result.strVal = ""
482  for i in 1..<n.len:
483    let a = getConstExpr(m, n[i], idgen, g)
484    if a == nil: return nil
485    result.strVal.add(getStrOrChar(a))
486
487proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
488  result = newSymNode(s, info)
489  if s.typ.kind != tyTypeDesc:
490    result.typ = newType(tyTypeDesc, idgen.nextTypeId, s.owner)
491    result.typ.addSonSkipIntLit(s.typ, idgen)
492  else:
493    result.typ = s.typ
494
495proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
496  result = nil
497  case n.kind
498  of nkSym:
499    var s = n.sym
500    case s.kind
501    of skEnumField:
502      result = newIntNodeT(toInt128(s.position), n, idgen, g)
503    of skConst:
504      case s.magic
505      of mIsMainModule: result = newIntNodeT(toInt128(ord(sfMainModule in m.flags)), n, idgen, g)
506      of mCompileDate: result = newStrNodeT(getDateStr(), n, g)
507      of mCompileTime: result = newStrNodeT(getClockStr(), n, g)
508      of mCpuEndian: result = newIntNodeT(toInt128(ord(CPU[g.config.target.targetCPU].endian)), n, idgen, g)
509      of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.targetOS].name), n, g)
510      of mHostCPU: result = newStrNodeT(platform.CPU[g.config.target.targetCPU].name.toLowerAscii, n, g)
511      of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[g.config.target.hostOS].name), n, g)
512      of mBuildCPU: result = newStrNodeT(platform.CPU[g.config.target.hostCPU].name.toLowerAscii, n, g)
513      of mAppType: result = getAppType(n, g)
514      of mIntDefine:
515        if isDefined(g.config, s.name.s):
516          try:
517            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseInt), n, idgen, g)
518          except ValueError:
519            localError(g.config, s.info,
520              "{.intdefine.} const was set to an invalid integer: '" &
521                g.config.symbols[s.name.s] & "'")
522        else:
523          result = copyTree(s.ast)
524      of mStrDefine:
525        if isDefined(g.config, s.name.s):
526          result = newStrNodeT(g.config.symbols[s.name.s], n, g)
527        else:
528          result = copyTree(s.ast)
529      of mBoolDefine:
530        if isDefined(g.config, s.name.s):
531          try:
532            result = newIntNodeT(toInt128(g.config.symbols[s.name.s].parseBool.int), n, idgen, g)
533          except ValueError:
534            localError(g.config, s.info,
535              "{.booldefine.} const was set to an invalid bool: '" &
536                g.config.symbols[s.name.s] & "'")
537        else:
538          result = copyTree(s.ast)
539      else:
540        result = copyTree(s.ast)
541    of skProc, skFunc, skMethod:
542      result = n
543    of skParam:
544      if s.typ != nil and s.typ.kind == tyTypeDesc:
545        result = newSymNodeTypeDesc(s, idgen, n.info)
546    of skType:
547      # XXX gensym'ed symbols can come here and cannot be resolved. This is
548      # dirty, but correct.
549      if s.typ != nil:
550        result = newSymNodeTypeDesc(s, idgen, n.info)
551    of skGenericParam:
552      if s.typ.kind == tyStatic:
553        if s.typ.n != nil and tfUnresolved notin s.typ.flags:
554          result = s.typ.n
555          result.typ = s.typ.base
556      elif s.typ.isIntLit:
557        result = s.typ.n
558      else:
559        result = newSymNodeTypeDesc(s, idgen, n.info)
560    else: discard
561  of nkCharLit..nkNilLit:
562    result = copyNode(n)
563  of nkIfExpr:
564    result = getConstIfExpr(m, n, idgen, g)
565  of nkCallKinds:
566    if n[0].kind != nkSym: return
567    var s = n[0].sym
568    if s.kind != skProc and s.kind != skFunc: return
569    try:
570      case s.magic
571      of mNone:
572        # If it has no sideEffect, it should be evaluated. But not here.
573        return
574      of mLow:
575        if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
576          result = newFloatNodeT(firstFloat(n[1].typ), n, g)
577        else:
578          result = newIntNodeT(firstOrd(g.config, n[1].typ), n, idgen, g)
579      of mHigh:
580        if skipTypes(n[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin
581            {tySequence, tyString, tyCstring, tyOpenArray, tyVarargs}:
582          if skipTypes(n[1].typ, abstractVarRange).kind in tyFloat..tyFloat64:
583            result = newFloatNodeT(lastFloat(n[1].typ), n, g)
584          else:
585            result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, idgen, g)
586        else:
587          var a = getArrayConstr(m, n[1], idgen, g)
588          if a.kind == nkBracket:
589            # we can optimize it away:
590            result = newIntNodeT(toInt128(a.len-1), n, idgen, g)
591      of mLengthOpenArray:
592        var a = getArrayConstr(m, n[1], idgen, g)
593        if a.kind == nkBracket:
594          # we can optimize it away! This fixes the bug ``len(134)``.
595          result = newIntNodeT(toInt128(a.len), n, idgen, g)
596        else:
597          result = magicCall(m, n, idgen, g)
598      of mLengthArray:
599        # It doesn't matter if the argument is const or not for mLengthArray.
600        # This fixes bug #544.
601        result = newIntNodeT(lengthOrd(g.config, n[1].typ), n, idgen, g)
602      of mSizeOf:
603        result = foldSizeOf(g.config, n, nil)
604      of mAlignOf:
605        result = foldAlignOf(g.config, n, nil)
606      of mOffsetOf:
607        result = foldOffsetOf(g.config, n, nil)
608      of mAstToStr:
609        result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
610      of mConStrStr:
611        result = foldConStrStr(m, n, idgen, g)
612      of mIs:
613        # The only kind of mIs node that comes here is one depending on some
614        # generic parameter and that's (hopefully) handled at instantiation time
615        discard
616      else:
617        result = magicCall(m, n, idgen, g)
618    except OverflowDefect:
619      localError(g.config, n.info, "over- or underflow")
620    except DivByZeroDefect:
621      localError(g.config, n.info, "division by zero")
622  of nkAddr:
623    var a = getConstExpr(m, n[0], idgen, g)
624    if a != nil:
625      result = n
626      n[0] = a
627  of nkBracket, nkCurly:
628    result = copyNode(n)
629    for i, son in n.pairs:
630      var a = getConstExpr(m, son, idgen, g)
631      if a == nil: return nil
632      result.add a
633    incl(result.flags, nfAllConst)
634  of nkRange:
635    var a = getConstExpr(m, n[0], idgen, g)
636    if a == nil: return
637    var b = getConstExpr(m, n[1], idgen, g)
638    if b == nil: return
639    result = copyNode(n)
640    result.add a
641    result.add b
642  #of nkObjConstr:
643  #  result = copyTree(n)
644  #  for i in 1..<n.len:
645  #    var a = getConstExpr(m, n[i][1])
646  #    if a == nil: return nil
647  #    result[i][1] = a
648  #  incl(result.flags, nfAllConst)
649  of nkPar, nkTupleConstr:
650    # tuple constructor
651    result = copyNode(n)
652    if (n.len > 0) and (n[0].kind == nkExprColonExpr):
653      for i, expr in n.pairs:
654        let exprNew = copyNode(expr) # nkExprColonExpr
655        exprNew.add expr[0]
656        let a = getConstExpr(m, expr[1], idgen, g)
657        if a == nil: return nil
658        exprNew.add a
659        result.add exprNew
660    else:
661      for i, expr in n.pairs:
662        let a = getConstExpr(m, expr, idgen, g)
663        if a == nil: return nil
664        result.add a
665    incl(result.flags, nfAllConst)
666  of nkChckRangeF, nkChckRange64, nkChckRange:
667    var a = getConstExpr(m, n[0], idgen, g)
668    if a == nil: return
669    if leValueConv(n[1], a) and leValueConv(a, n[2]):
670      result = a              # a <= x and x <= b
671      result.typ = n.typ
672    else:
673      localError(g.config, n.info,
674        "conversion from $1 to $2 is invalid" %
675          [typeToString(n[0].typ), typeToString(n.typ)])
676  of nkStringToCString, nkCStringToString:
677    var a = getConstExpr(m, n[0], idgen, g)
678    if a == nil: return
679    result = a
680    result.typ = n.typ
681  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
682    var a = getConstExpr(m, n[1], idgen, g)
683    if a == nil: return
684    result = foldConv(n, a, idgen, g, check=true)
685  of nkDerefExpr, nkHiddenDeref:
686    let a = getConstExpr(m, n[0], idgen, g)
687    if a != nil and a.kind == nkNilLit:
688      result = nil
689      #localError(g.config, n.info, "nil dereference is not allowed")
690  of nkCast:
691    var a = getConstExpr(m, n[1], idgen, g)
692    if a == nil: return
693    if n.typ != nil and n.typ.kind in NilableTypes:
694      # we allow compile-time 'cast' for pointer types:
695      result = a
696      result.typ = n.typ
697  of nkBracketExpr: result = foldArrayAccess(m, n, idgen, g)
698  of nkDotExpr: result = foldFieldAccess(m, n, idgen, g)
699  of nkCheckedFieldExpr:
700    assert n[0].kind == nkDotExpr
701    result = foldFieldAccess(m, n[0], idgen, g)
702  of nkStmtListExpr:
703    var i = 0
704    while i <= n.len - 2:
705      if n[i].kind in {nkComesFrom, nkCommentStmt, nkEmpty}: i.inc
706      else: break
707    if i == n.len - 1:
708      result = getConstExpr(m, n[i], idgen, g)
709  else:
710    discard
711