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