# # # The Nimrod Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module implements the renderer of the standard Nimrod representation. import lexer, options, idents, strutils, ast, msgs, lists type TRenderFlag* = enum renderNone, renderNoBody, renderNoComments, renderDocComments, renderNoPragmas, renderIds, renderNoProcDefs TRenderFlags* = set[TRenderFlag] TRenderTok*{.final.} = object kind*: TTokType length*: int16 TRenderTokSeq* = seq[TRenderTok] TSrcGen*{.final.} = object indent*: int lineLen*: int pos*: int # current position for iteration over the buffer idx*: int # current token index for iteration over the buffer tokens*: TRenderTokSeq buf*: string pendingNL*: int # negative if not active; else contains the # indentation value comStack*: seq[PNode] # comment stack flags*: TRenderFlags checkAnon: bool # we're in a context that can contain sfAnon proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {}) proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) # implementation # We render the source code in a two phases: The first # determines how long the subtree will likely be, the second # phase appends to a buffer that will be the output. proc isKeyword*(s: string): bool = var i = getIdent(s) if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): result = true proc renderDefinitionName*(s: PSym, noQuotes = false): string = ## Returns the definition name of the symbol. ## ## If noQuotes is false the symbol may be returned in backticks. This will ## happen if the name happens to be a keyword or the first character is not ## part of the SymStartChars set. let x = s.name.s if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)): result = x else: result = '`' & x & '`' const IndentWidth = 2 longIndentWid = 4 MaxLineLen = 80 LineCommentColumn = 30 proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = g.comStack = @[] g.tokens = @[] g.indent = 0 g.lineLen = 0 g.pos = 0 g.idx = 0 g.buf = "" g.flags = renderFlags g.pendingNL = -1 g.checkAnon = false proc addTok(g: var TSrcGen, kind: TTokType, s: string) = var length = len(g.tokens) setLen(g.tokens, length + 1) g.tokens[length].kind = kind g.tokens[length].length = int16(len(s)) add(g.buf, s) proc addPendingNL(g: var TSrcGen) = if g.pendingNL >= 0: addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL)) g.lineLen = g.pendingNL g.pendingNL = - 1 proc putNL(g: var TSrcGen, indent: int) = if g.pendingNL >= 0: addPendingNL(g) else: addTok(g, tkSpaces, "\n") g.pendingNL = indent g.lineLen = indent proc putNL(g: var TSrcGen) = putNL(g, g.indent) proc optNL(g: var TSrcGen, indent: int) = g.pendingNL = indent g.lineLen = indent # BUGFIX proc optNL(g: var TSrcGen) = optNL(g, g.indent) proc indentNL(g: var TSrcGen) = inc(g.indent, IndentWidth) g.pendingNL = g.indent g.lineLen = g.indent proc dedent(g: var TSrcGen) = dec(g.indent, IndentWidth) assert(g.indent >= 0) if g.pendingNL > IndentWidth: dec(g.pendingNL, IndentWidth) dec(g.lineLen, IndentWidth) proc put(g: var TSrcGen, kind: TTokType, s: string) = addPendingNL(g) if len(s) > 0: addTok(g, kind, s) inc(g.lineLen, len(s)) proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = # use this for tokens over multiple lines. addP
discard """
errormsg: "type mismatch: got <TKind>"
file: "tadrdisc.nim"
line: 20
"""
# Test that the address of a discriminants cannot be taken
type
TKind = enum ka, kb, kc
TA = object
case k: TKind
of ka: x, y: int
of kb: a, b: string
of kc: c, d: float
proc setKind(k: var TKind) =
k = kc
var a: TA
setKind(a.k)