typesrenderer.nim 5.0 KB

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