typesrenderer.nim 4.9 KB

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