typesrenderer.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 and n[0].kind == nkFormalParams:
  61. let params = n[0]
  62. assert params.len > 0
  63. result = "proc("
  64. for i in 1..<params.len: result.add(renderType(params[i], toNormalize) & ',')
  65. result[^1] = ')'
  66. else:
  67. result = "proc"
  68. of nkIdentDefs:
  69. assert n.len >= 3
  70. let typePos = n.len - 2
  71. let typeStr = renderType(n[typePos], toNormalize)
  72. result = typeStr
  73. for i in 1..<typePos:
  74. assert n[i].kind in {nkSym, nkIdent}
  75. result.add(',' & typeStr)
  76. of nkTupleTy:
  77. result = "tuple["
  78. for i in 0..<n.len: result.add(renderType(n[i], toNormalize) & ',')
  79. result[^1] = ']'
  80. of nkBracketExpr:
  81. assert n.len >= 2
  82. result = renderType(n[0], toNormalize) & '['
  83. for i in 1..<n.len: result.add(renderType(n[i], toNormalize) & ',')
  84. result[^1] = ']'
  85. of nkCommand:
  86. result = renderType(n[0], toNormalize)
  87. for i in 1..<n.len:
  88. if i > 1: result.add ", "
  89. result.add(renderType(n[i], toNormalize))
  90. else: result = ""
  91. proc renderParamNames*(n: PNode, toNormalize=false): seq[string] =
  92. ## Returns parameter names of routine `n`.
  93. doAssert n.kind == nkFormalParams
  94. case n.kind
  95. of nkFormalParams:
  96. for i in 1..<n.len:
  97. if n[i].kind == nkIdentDefs:
  98. # These are parameter names + type + default value node.
  99. let typePos = n[i].len - 2
  100. for j in 0..<typePos:
  101. result.add mayNormalize($n[i][j])
  102. else: # error
  103. result.add($n[i])
  104. else: #error
  105. result.add $n
  106. proc renderParamTypes*(found: var seq[string], n: PNode, toNormalize=false) =
  107. ## Recursive helper, adds to `found` any types, or keeps diving the AST.
  108. ##
  109. ## The normal `doc` generator doesn't include .typ information, so the
  110. ## function won't render types for parameters with default values. The `doc`
  111. ## generator does include the information.
  112. case n.kind
  113. of nkFormalParams:
  114. for i in 1..<n.len: renderParamTypes(found, n[i], toNormalize)
  115. of nkIdentDefs:
  116. # These are parameter names + type + default value node.
  117. let typePos = n.len - 2
  118. assert typePos > 0
  119. var typeStr = renderType(n[typePos], toNormalize)
  120. if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
  121. # Try with the last node, maybe its a default value.
  122. let typ = n[typePos+1].typ
  123. if not typ.isNil: typeStr = typeToString(typ, preferExported)
  124. if typeStr.len < 1: return
  125. for i in 0..<typePos:
  126. found.add(typeStr)
  127. else:
  128. found.add($n)
  129. #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
  130. proc renderParamTypes*(n: PNode, sep = defaultParamSeparator,
  131. toNormalize=false): string =
  132. ## Returns the types contained in `n` joined by `sep`.
  133. ##
  134. ## This proc expects to be passed as `n` the parameters of any callable. The
  135. ## string output is meant for the HTML renderer. If there are no parameters,
  136. ## the empty string is returned. The parameters will be joined by `sep` but
  137. ## other characters may appear too, like ``[]`` or ``|``.
  138. result = ""
  139. var found: seq[string] = @[]
  140. renderParamTypes(found, n, toNormalize)
  141. if found.len > 0:
  142. result = found.join(sep)
  143. proc renderOutType*(n: PNode, toNormalize=false): string =
  144. assert n.kind == nkFormalParams
  145. result = renderType(n[0], toNormalize)