File: typesrenderer.nim

package info (click to toggle)
nim 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,911,644 kB
  • sloc: sh: 24,603; ansic: 1,761; python: 1,492; makefile: 1,013; sql: 298; asm: 141; xml: 13
file content (160 lines) | stat: -rw-r--r-- 5,110 bytes parent folder | download
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

import renderer, ast, types
import std/strutils

when defined(nimPreviewSlimSystem):
  import std/assertions


const defaultParamSeparator* = ","

template mayNormalize(s: string): string =
  if toNormalize:
    s.nimIdentNormalize
  else:
    s

proc renderPlainSymbolName*(n: PNode): string =
  ## Returns the first non '*' nkIdent node from the tree.
  ##
  ## Use this on documentation name nodes to extract the *raw* symbol name,
  ## without decorations, parameters, or anything. That can be used as the base
  ## for the HTML hyperlinks.
  case n.kind
  of nkPostfix, nkAccQuoted:
    result = renderPlainSymbolName(n[^1])
  of nkIdent:
    result = n.ident.s
  of nkSym:
    result = n.sym.renderDefinitionName(noQuotes = true)
  of nkPragmaExpr:
    result = renderPlainSymbolName(n[0])
  else:
    result = ""
    #internalError(n.info, "renderPlainSymbolName() with " & $n.kind)

proc renderType(n: PNode, toNormalize: bool): string =
  ## Returns a string with the node type or the empty string.
  ## This proc should be kept in sync with `toLangSymbols` from
  ## ``lib/packages/docutils/dochelpers.nim``.
  case n.kind:
  of nkIdent: result = mayNormalize(n.ident.s)
  of nkSym: result = mayNormalize(typeToString(n.sym.typ))
  of nkVarTy:
    if n.len == 1:
      result = renderType(n[0], toNormalize)
    else:
      result = "var"
  of nkRefTy:
    if n.len == 1:
      result = "ref." & renderType(n[0], toNormalize)
    else:
      result = "ref"
  of nkPtrTy:
    if n.len == 1:
      result = "ptr." & renderType(n[0], toNormalize)
    else:
      result = "ptr"
  of nkProcTy:
    assert n.len != 1
    if n.len > 1 and n[0].kind == nkFormalParams:
      let params = n[0]
      assert params.len > 0
      result = "proc("
      for i in 1..<params.len: result.add(renderType(params[i], toNormalize) & ',')
      result[^1] = ')'
    else:
      result = "proc"
  of nkIdentDefs:
    assert n.len >= 3
    let typePos = n.len - 2
    let typeStr = renderType(n[typePos], toNormalize)
    result = typeStr
    for i in 1..<typePos:
      assert n[i].kind in {nkSym, nkIdent}
      result.add(',' & typeStr)
  of nkTupleTy:
    result = "tuple["
    for i in 0..<n.len: result.add(renderType(n[i], toNormalize) & ',')
    result[^1] = ']'
  of nkBracketExpr:
    assert n.len >= 2
    result = renderType(n[0], toNormalize) & '['
    for i in 1..<n.len: result.add(renderType(n[i], toNormalize) & ',')
    result[^1] = ']'
  of nkCommand:
    result = renderType(n[0], toNormalize)
    for i in 1..<n.len:
      if i > 1: result.add ", "
      result.add(renderType(n[i], toNormalize))
  else: result = ""


proc renderParamNames*(n: PNode, toNormalize=false): seq[string] =
  ## Returns parameter names of routine `n`.
  result = @[]
  doAssert n.kind == nkFormalParams
  case n.kind
  of nkFormalParams:
    for i in 1..<n.len:
      if n[i].kind == nkIdentDefs:
        # These are parameter names + type + default value node.
        let typePos = n[i].len - 2
        for j in 0..<typePos:
          result.add mayNormalize($n[i][j])
      else:  # error
        result.add($n[i])
  else:  #error
    result.add $n


proc renderParamTypes*(found: var seq[string], n: PNode, toNormalize=false) =
  ## Recursive helper, adds to `found` any types, or keeps diving the AST.
  ##
  ## The normal `doc` generator doesn't include .typ information, so the
  ## function won't render types for parameters with default values. The `doc`
  ## generator does include the information.
  case n.kind
  of nkFormalParams:
    for i in 1..<n.len: renderParamTypes(found, n[i], toNormalize)
  of nkIdentDefs:
    # These are parameter names + type + default value node.
    let typePos = n.len - 2
    assert typePos > 0
    var typeStr = renderType(n[typePos], toNormalize)
    if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
      # Try with the last node, maybe its a default value.
      let typ = n[typePos+1].typ
      if not typ.isNil: typeStr = typeToString(typ, preferExported)
      if typeStr.len < 1: return
    for i in 0..<typePos:
      found.add(typeStr)
  else:
    found.add($n)
    #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)

proc renderParamTypes*(n: PNode, sep = defaultParamSeparator,
                       toNormalize=false): string =
  ## Returns the types contained in `n` joined by `sep`.
  ##
  ## This proc expects to be passed as `n` the parameters of any callable. The
  ## string output is meant for the HTML renderer. If there are no parameters,
  ## the empty string is returned. The parameters will be joined by `sep` but
  ## other characters may appear too, like ``[]`` or ``|``.
  result = ""
  var found: seq[string] = @[]
  renderParamTypes(found, n, toNormalize)
  if found.len > 0:
    result = found.join(sep)

proc renderOutType*(n: PNode, toNormalize=false): string =
  assert n.kind == nkFormalParams
  result = renderType(n[0], toNormalize)