typesrenderer.nim 3.8 KB

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