summary refs log tree commit diff stats
path: root/compiler/ccgtrav.nim
blob: 8bb82028397d0bd828acf1f93f30654f6cb25f85 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* G
#
#
#           The Nim Compiler
#        (c) Copyright 2013 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Generates traversal procs for the C backend. Traversal procs are only an
## optimization; the GC works without them too.

# included from cgen.nim

type
  TTraversalClosure = object
    p: BProc
    visitorFrmt: string

proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)

proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
  if n == nil: return
  case n.kind
  of nkRecList:
    for i in countup(0, sonsLen(n) - 1):
      genTraverseProc(c, accessor, n.sons[i])
  of nkRecCase:
    if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
    var p = c.p
    let disc = n.sons[0].sym
    lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
    for i in countup(1, sonsLen(n) - 1):
      let branch = n.sons[i]
      assert branch.kind in {nkOfBranch, nkElse}
      if branch.kind == nkOfBranch:
        genCaseRange(c.p, branch)
      else:
        lineF(p, cpsStmts, "default:$n")
      genTraverseProc(c, accessor, lastSon(branch))
      lineF(p, cpsStmts, "break;$n")
    lineF(p, cpsStmts, "} $n")
  of nkSym:
    let field = n.sym
    if field.loc.t == nil:
      internalError(n.info, "genTraverseProc()")
    genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
  else: internalError(n.info, "genTraverseProc()")

proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
  if not m.compileToCpp:
    result = ropef("$1.Sup", accessor)
  else:
    result = accessor

proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
  if typ == nil: return
  var p = c.p
  case typ.kind
  of tyGenericInst, tyGenericBody, tyTypeDesc:
    genTraverseProc(c, accessor, lastSon(typ))
  of tyArrayConstr, tyArray:
    let arraySize = lengthOrd(typ.sons[0])
    var i: TLoc
    getTemp(p, getSysType(tyInt), i)
    linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
            i.r, arraySize.toRope)
    genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
    lineF(p, cpsStmts, "}$n")
  of tyObject:
    for i in countup(0, sonsLen(typ) - 1):
      genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
    if typ.n != nil: genTraverseProc(c, accessor, typ.n)
  of tyTuple:
    let typ = getUniqueType(typ)
    for i in countup(0, sonsLen(typ) - 1):
      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
  of tyRef, tyString, tySequence:
    lineCg(p, cpsStmts, c.visitorFrmt, accessor)
  of tyProc:
    if typ.callConv == ccClosure:
      lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
  else:
    discard

proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
  var p = c.p
  assert typ.kind == tySequence  
  var i: TLoc
  getTemp(p, getSysType(tyInt), i)
  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
      i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
  genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
  lineF(p, cpsStmts, "}$n")
  
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
  var c: TTraversalClosure
  var p = newProc(nil, m)
  result = getGlobalTempName()
  
  case reason
  of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
  else: assert false
  
  let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
  
  let t = getTypeDesc(m, typ)
  lineF(p, cpsLocals, "$1 a;$n", t)
  lineF(p, cpsInit, "a = ($1)p;$n", t)
  
  c.p = p
  assert typ.kind != tyTypeDesc
  if typ.kind == tySequence:
    genTraverseProcSeq(c, "a".toRope, typ)
  else:
    if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
      # C's arrays are broken beyond repair:
      genTraverseProc(c, "a".toRope, typ.sons[0])
    else:
      genTraverseProc(c, "(*a)".toRope, typ.sons[0])
  
  let generatedProc = ropef("$1 {$n$2$3$4}$n",
        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
  
  m.s[cfsProcHeaders].appf("$1;$n", header)
  m.s[cfsProcs].app(generatedProc)

proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
  discard genTypeInfo(m, s.loc.t)
  
  var c: TTraversalClosure
  var p = newProc(nil, m)
  var sLoc = s.loc.r
  result = getGlobalTempName()
  
  if sfThread in s.flags and emulatedThreadVars():
    accessThreadLocalVar(p, s)
    sLoc = con("NimTV->", sLoc)
    
  c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
  c.p = p
  let header = ropef("N_NIMCALL(void, $1)()", result)
  genTraverseProc(c, sLoc, s.loc.t)
  
  let generatedProc = ropef("$1 {$n$2$3$4}$n",
        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
  
  m.s[cfsProcHeaders].appf("$1;$n", header)
  m.s[cfsProcs].app(generatedProc)