typesrenderer.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. import renderer, ast, types
  10. import std/strutils
  11. when defined(nimPreviewSlimSystem):
  12. import std/assertions
  13. const defaultParamSeparator* = ","
  14. template mayNormalize(s: string): string =
  15. if toNormalize:
  16. s.nimIdentNormalize
  17. else:
  18. s
  19. proc renderPlainSymbolName*(n: PNode): string =
  20. ## Returns the first non '*' nkIdent node from the tree.
  21. ##
  22. ## Use this on documentation name nodes to extract the *raw* symbol name,
  23. ## without decorations, parameters, or anything. That can be used as the base
  24. ## for the HTML hyperlinks.
  25. case n.kind
  26. of nkPostfix, nkAccQuoted:
  27. result = renderPlainSymbolName(n[^1])
  28. of nkIdent:
  29. result = n.ident.s
  30. of nkSym:
  31. result = n.sym.renderDefinitionName(noQuotes = true)
  32. of nkPragmaExpr:
  33. result = renderPlainSymbolName(n[0])
  34. else:
  35. result = ""
  36. #internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
  37. proc renderType(n: PNode, toNormalize: bool): string =
  38. ## Returns a string with the node type or the empty string.
  39. ## This proc should be kept in sync with `toLangSymbols` from
  40. ## ``lib/packages/docutils/dochelpers.nim``.
  41. case n.kind:
  42. of nkIdent: result = mayNormalize(n.ident.s)
  43. of nkSym: result = mayNormalize(typeToString(n.sym.typ))
  44. of nkVarTy:
  45. if n.len == 1:
  46. result = renderType(n[0], toNormalize)
  47. else:
  48. result = "var"
  49. of nkRefTy:
  50. if n.len == 1:
  51. result = "ref." & renderType(n[0], toNormalize)
  52. else:
  53. result = "ref"
  54. of nkPtrTy:
  55. if n.len == 1:
  56. result = "ptr." & renderType(n[0], toNormalize)
  57. else:
  58. result = "ptr"
  59. of nkProcTy:
  60. assert n.len != 1
  61. if n.len > 1 and n[0].kind == nkFormalParams:
  62. let params = n[0]
  63. assert params.len > 0
  64. result = "proc("
  65. for i in 1..<params.len: result.add(renderType(params[i], toNormalize) & ',')
  66. result[^1] = ')'
  67. else:
  68. result = "proc"
  69. of nkIdentDefs:
  70. assert n.len >= 3
  71. let typePos = n.len - 2
  72. let typeStr = renderType(n[typePos], toNormalize)
  73. result = typeStr
  74. for i in 1..<typePos:
  75. assert n[i].kind in {nkSym, nkIdent}
  76. result.add(',' & typeStr)
  77. of nkTupleTy:
  78. result = "tuple["
  79. for i in 0..<n.len: result.add(renderType(n[i], toNormalize) & ',')
  80. result[^1] = ']'
  81. of nkBracketExpr:
  82. assert n.len >= 2
  83. result = renderType(n[0], toNormalize) & '['
  84. for i in 1..<n.len: result.add(renderType(n[i], toNormalize) & ',')
  85. result[^1] = ']'
  86. of nkCommand:
  87. result = renderType(n[0], toNormalize)
  88. for i in 1..<n.len:
  89. if i > 1: result.add ", "
  90. result.add(renderType(n[i], toNormalize))
  91. else: result = ""
  92. proc renderParamNames*(n: PNode, toNormalize=false): seq[string] =
  93. ## Returns parameter names of routine `n`.
  94. result = @[]
  95. doAssert n.kind == nkFormalParams
  96. case n.kind
  97. of nkFormalParams:
  98. for i in 1..<n.len:
  99. if n[i].kind == nkIdentDefs:
  100. # These are parameter names + type + default value node.
  101. let typePos = n[i].len - 2
  102. for j in 0..<typePos:
  103. result.add mayNormalize($n[i][j])
  104. else: # error
  105. result.add($n[i])
  106. else: #error
  107. result.add $n
  108. proc renderParamTypes*(found: var seq[string], n: PNode, toNormalize=false) =
  109. ## Recursive helper, adds to `found` any types, or keeps diving the AST.
  110. ##
  111. ## The normal `doc` generator doesn't include .typ information, so the
  112. ## function won't render types for parameters with default values. The `doc`
  113. ## generator does include the information.
  114. case n.kind
  115. of nkFormalParams:
  116. for i in 1..<n.len: renderParamTypes(found, n[i], toNormalize)
  117. of nkIdentDefs:
  118. # These are parameter names + type + default value node.
  119. let typePos = n.len - 2
  120. assert typePos > 0
  121. var typeStr = renderType(n[typePos], toNormalize)
  122. if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
  123. # Try with the last node, maybe its a default value.
  124. let typ = n[typePos+1].typ
  125. if not typ.isNil: typeStr = typeToString(typ, preferExported)
  126. if typeStr.len < 1: return
  127. for i in 0..<typePos:
  128. found.add(typeStr)
  129. else:
  130. found.add($n)
  131. #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
  132. proc renderParamTypes*(n: PNode, sep = defaultParamSeparator,
  133. toNormalize=false): string =
  134. ## Returns the types contained in `n` joined by `sep`.
  135. ##
  136. ## This proc expects to be passed as `n` the parameters of any callable. The
  137. ## string output is meant for the HTML renderer. If there are no parameters,
  138. ## the empty string is returned. The parameters will be joined by `sep` but
  139. ## other characters may appear too, like ``[]`` or ``|``.
  140. result = ""
  141. var found: seq[string] = @[]
  142. renderParamTypes(found, n, toNormalize)
  143. if found.len > 0:
  144. result = found.join(sep)
  145. proc renderOutType*(n: PNode, toNormalize=false): string =
  146. assert n.kind == nkFormalParams
  147. result = renderType(n[0], toNormalize)