diff options
Diffstat (limited to 'nim/rnimsyn.pas')
-rwxr-xr-x | nim/rnimsyn.pas | 1458 |
1 files changed, 0 insertions, 1458 deletions
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas deleted file mode 100755 index ec1e9571e..000000000 --- a/nim/rnimsyn.pas +++ /dev/null @@ -1,1458 +0,0 @@ -// -// -// The Nimrod Compiler -// (c) Copyright 2009 Andreas Rumpf -// -// See the file "copying.txt", included in this -// distribution, for details about the copyright. -// - -unit rnimsyn; - -// This module implements the renderer of the standard Nimrod representation. - -{$include config.inc} - -interface - -uses - nsystem, charsets, scanner, options, idents, strutils, ast, msgs, - lists; - -type - TRenderFlag = (renderNone, renderNoBody, renderNoComments, - renderDocComments, renderNoPragmas, renderIds); - TRenderFlags = set of TRenderFlag; - - TRenderTok = record - kind: TTokType; - len: int16; - end; - TRenderTokSeq = array of TRenderTok; - - TSrcGen = record - 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: array of PNode; // comment stack - flags: TRenderFlags; - end; - -procedure renderModule(n: PNode; const filename: string; - renderFlags: TRenderFlags = {@set}[]); - -function renderTree(n: PNode; renderFlags: TRenderFlags = {@set}[]): string; - -procedure initTokRender(var r: TSrcGen; n: PNode; - renderFlags: TRenderFlags = {@set}[]); -procedure getNextTok(var r: TSrcGen; var kind: TTokType; var literal: 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. - -const - IndentWidth = 2; - longIndentWid = 4; - MaxLineLen = 80; - LineCommentColumn = 30; - -procedure InitSrcGen(out g: TSrcGen; renderFlags: TRenderFlags); -begin -{@ignore} - fillChar(g, sizeof(g), 0); - g.comStack := nil; - g.tokens := nil; -{@emit - g.comStack := @[];} -{@emit - g.tokens := @[];} - g.indent := 0; - g.lineLen := 0; - g.pos := 0; - g.idx := 0; - g.buf := ''; - g.flags := renderFlags; - g.pendingNL := -1; -end; - -{@ignore} -procedure add(var dest: string; const src: string); -begin - dest := dest +{&} src; -end; -{@emit} - -procedure addTok(var g: TSrcGen; kind: TTokType; const s: string); -var - len: int; -begin - len := length(g.tokens); - setLength(g.tokens, len+1); - g.tokens[len].kind := kind; - g.tokens[len].len := int16(length(s)); - add(g.buf, s); -end; - -procedure addPendingNL(var g: TSrcGen); -begin - if g.pendingNL >= 0 then begin - addTok(g, tkInd, NL+{&}repeatChar(g.pendingNL)); - g.lineLen := g.pendingNL; - g.pendingNL := -1; - end -end; - -procedure putNL(var g: TSrcGen; indent: int); overload; -begin - if g.pendingNL >= 0 then - addPendingNL(g) - else - addTok(g, tkInd, NL); - g.pendingNL := indent; - g.lineLen := indent; -end; - -procedure putNL(var g: TSrcGen); overload; -begin - putNL(g, g.indent); -end; - -procedure optNL(var g: TSrcGen; indent: int); overload; -begin - g.pendingNL := indent; - g.lineLen := indent; // BUGFIX -end; - -procedure optNL(var g: TSrcGen); overload; -begin - optNL(g, g.indent) -end; - -procedure indentNL(var g: TSrcGen); -begin - inc(g.indent, indentWidth); - g.pendingNL := g.indent; - g.lineLen := g.indent; -end; - -procedure Dedent(var g: TSrcGen); -begin - dec(g.indent, indentWidth); - assert(g.indent >= 0); - if g.pendingNL > indentWidth then begin - Dec(g.pendingNL, indentWidth); - Dec(g.lineLen, indentWidth) - end -end; - -procedure put(var g: TSrcGen; const kind: TTokType; const s: string); -begin - addPendingNL(g); - if length(s) > 0 then begin - addTok(g, kind, s); - inc(g.lineLen, length(s)); - end -end; - -procedure putLong(var g: TSrcGen; const kind: TTokType; const s: string; - lineLen: int); -// use this for tokens over multiple lines. -begin - addPendingNL(g); - addTok(g, kind, s); - g.lineLen := lineLen; -end; - -// ----------------------- helpers -------------------------------------------- - -function toNimChar(c: Char): string; -begin - case c of - #0: result := '\0'; - #1..#31, #128..#255: result := '\x' + strutils.toHex(ord(c), 2); - '''', '"', '\': result := '\' + c; - else result := c + '' - end; -end; - -function makeNimString(const s: string): string; -var - i: int; -begin - result := '"' + ''; - for i := strStart to length(s)+strStart-1 do add(result, toNimChar(s[i])); - addChar(result, '"'); -end; - -procedure putComment(var g: TSrcGen; s: string); -var - i, j, ind, comIndent: int; - isCode: bool; - com: string; -begin - {@ignore} s := s + #0; {@emit} - i := strStart; - comIndent := 1; - isCode := (length(s) >= 2) and (s[strStart+1] <> ' '); - ind := g.lineLen; - com := ''; - while true do begin - case s[i] of - #0: break; - #13: begin - put(g, tkComment, com); - com := ''; - inc(i); - if s[i] = #10 then inc(i); - optNL(g, ind); - end; - #10: begin - put(g, tkComment, com); - com := ''; - inc(i); - optNL(g, ind); - end; - '#': begin - addChar(com, s[i]); - inc(i); - comIndent := 0; - while s[i] = ' ' do begin - addChar(com, s[i]); - inc(i); inc(comIndent); - end - end; - ' ', #9: begin - addChar(com, s[i]); - inc(i); - end - else begin - // we may break the comment into a multi-line comment if the line - // gets too long: - - // compute length of the following word: - j := i; - while s[j] > ' ' do inc(j); - if not isCode and (g.lineLen + (j-i) > MaxLineLen) then begin - put(g, tkComment, com); - com := ''; - optNL(g, ind); - com := com +{&} '#' +{&} repeatChar(comIndent); - end; - while s[i] > ' ' do begin - addChar(com, s[i]); - inc(i); - end - end - end - end; - put(g, tkComment, com); - optNL(g); -end; - -function maxLineLength(s: string): int; -var - i, linelen: int; -begin - {@ignore} s := s + #0; {@emit} - result := 0; - i := strStart; - lineLen := 0; - while true do begin - case s[i] of - #0: break; - #13: begin - inc(i); - if s[i] = #10 then inc(i); - result := max(result, lineLen); - lineLen := 0; - end; - #10: begin - inc(i); - result := max(result, lineLen); - lineLen := 0; - end; - else begin - inc(lineLen); inc(i); - end - end - end -end; - -procedure putRawStr(var g: TSrcGen; kind: TTokType; const s: string); -var - i, hi: int; - str: string; -begin - i := strStart; - hi := length(s)+strStart-1; - str := ''; - while i <= hi do begin - case s[i] of - #13: begin - put(g, kind, str); - str := ''; - inc(i); - if (i <= hi) and (s[i] = #10) then inc(i); - optNL(g, 0); - end; - #10: begin - put(g, kind, str); - str := ''; - inc(i); - optNL(g, 0); - end; - else begin - addChar(str, s[i]); - inc(i) - end - end - end; - put(g, kind, str); -end; - -function containsNL(const s: string): bool; -var - i: int; -begin - for i := strStart to length(s)+strStart-1 do - case s[i] of - #13, #10: begin result := true; exit end; - else begin end - end; - result := false -end; - -procedure pushCom(var g: TSrcGen; n: PNode); -var - len: int; -begin - len := length(g.comStack); - setLength(g.comStack, len+1); - g.comStack[len] := n; -end; - -procedure popAllComs(var g: TSrcGen); -begin - setLength(g.comStack, 0); -end; - -procedure popCom(var g: TSrcGen); -begin - setLength(g.comStack, length(g.comStack)-1); -end; - -const - Space = ' '+''; - -function shouldRenderComment(var g: TSrcGen; n: PNode): bool; -begin - result := false; - if n.comment <> snil then - result := not (renderNoComments in g.flags) or - (renderDocComments in g.flags) and startsWith(n.comment, '##'); -end; - -procedure gcom(var g: TSrcGen; n: PNode); -var - ml: int; -begin - assert(n <> nil); - if shouldRenderComment(g, n) then begin - if (g.pendingNL < 0) and (length(g.buf) > 0) - and (g.buf[length(g.buf)] <> ' ') then - put(g, tkSpaces, Space); - // Before long comments we cannot make sure that a newline is generated, - // because this might be wrong. But it is no problem in practice. - if (g.pendingNL < 0) and (length(g.buf) > 0) - and (g.lineLen < LineCommentColumn) then begin - ml := maxLineLength(n.comment); - if ml+LineCommentColumn <= maxLineLen then - put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen)); - end; - putComment(g, n.comment); - //assert(g.comStack[high(g.comStack)] = n); - end -end; - -procedure gcoms(var g: TSrcGen); -var - i: int; -begin - for i := 0 to high(g.comStack) do gcom(g, g.comStack[i]); - popAllComs(g); -end; - -// ---------------------------------------------------------------------------- - -function lsub(n: PNode): int; forward; - -function litAux(n: PNode; x: biggestInt; size: int): string; -begin - if nfBase2 in n.flags then result := '0b' + toBin(x, size*8) - else if nfBase8 in n.flags then result := '0o' + toOct(x, size*3) - else if nfBase16 in n.flags then result := '0x' + toHex(x, size*2) - else result := toString(x) -end; - -function atom(n: PNode): string; -var - f: float32; -begin - case n.kind of - nkEmpty: result := ''; - nkIdent: result := n.ident.s; - nkSym: result := n.sym.name.s; - nkStrLit: result := makeNimString(n.strVal); - nkRStrLit: result := 'r"' + n.strVal + '"'; - nkTripleStrLit: result := '"""' + n.strVal + '"""'; - nkCharLit: result := '''' + toNimChar(chr(int(n.intVal))) + ''''; - nkIntLit: result := litAux(n, n.intVal, 4); - nkInt8Lit: result := litAux(n, n.intVal, 1) + '''i8'; - nkInt16Lit: result := litAux(n, n.intVal, 2) + '''i16'; - nkInt32Lit: result := litAux(n, n.intVal, 4) + '''i32'; - nkInt64Lit: result := litAux(n, n.intVal, 8) + '''i64'; - nkFloatLit: begin - if n.flags * [nfBase2, nfBase8, nfBase16] = [] then - result := toStringF(n.floatVal) - else - result := litAux(n, ({@cast}PInt64(addr(n.floatVal)))^, 8); - end; - nkFloat32Lit: begin - if n.flags * [nfBase2, nfBase8, nfBase16] = [] then - result := toStringF(n.floatVal) + '''f32' - else begin - f := n.floatVal; - result := litAux(n, ({@cast}PInt32(addr(f)))^, 4) + '''f32' - end; - end; - nkFloat64Lit: begin - if n.flags * [nfBase2, nfBase8, nfBase16] = [] then - result := toStringF(n.floatVal) + '''f64' - else - result := litAux(n, ({@cast}PInt64(addr(n.floatVal)))^, 8) + '''f64'; - end; - nkNilLit: result := 'nil'; - nkType: begin - if (n.typ <> nil) and (n.typ.sym <> nil) then result := n.typ.sym.name.s - else result := '[type node]'; - end; - else InternalError('rnimsyn.atom ' + nodeKindToStr[n.kind]); - end -end; - -// --------------------------------------------------------------------------- - -function lcomma(n: PNode; start: int = 0; theEnd: int = -1): int; -var - i: int; -begin - assert(theEnd < 0); - result := 0; - for i := start to sonsLen(n)+theEnd do begin - inc(result, lsub(n.sons[i])); - inc(result, 2); // for ``, `` - end; - if result > 0 then dec(result, 2); // last does not get a comma! -end; - -function lsons(n: PNode; start: int = 0; theEnd: int = -1): int; -var - i: int; -begin - assert(theEnd < 0); - result := 0; - for i := start to sonsLen(n)+theEnd do inc(result, lsub(n.sons[i])); -end; - -function lsub(n: PNode): int; -// computes the length of a tree -var - L: int; -begin - if n = nil then begin result := 0; exit end; - if n.comment <> snil then begin result := maxLineLen+1; exit end; - case n.kind of - nkTripleStrLit: begin - if containsNL(n.strVal) then result := maxLineLen+1 - else result := length(atom(n)); - end; - nkEmpty..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: - result := length(atom(n)); - nkCall, nkBracketExpr, nkConv: result := lsub(n.sons[0])+lcomma(n, 1)+2; - nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: begin - result := lsub(n.sons[1]); - end; - nkCast: result := lsub(n.sons[0])+lsub(n.sons[1])+length('cast[]()'); - nkAddr: result := lsub(n.sons[0])+length('addr()'); - nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]); - nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1; - nkExprEqExpr, nkAsgn, nkFastAsgn: result := lsons(n)+3; - nkPar, nkCurly, nkBracket: result := lcomma(n)+2; - nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1; - nkTupleTy: result := lcomma(n)+length('tuple[]'); - nkDotExpr: result := lsons(n)+1; - nkBind: result := lsons(n)+length('bind_'); - nkCheckedFieldExpr: result := lsub(n.sons[0]); - nkLambda: result := lsons(n)+length('lambda__=_'); - nkConstDef, nkIdentDefs: begin - result := lcomma(n, 0, -3); - L := sonsLen(n); - if n.sons[L-2] <> nil then - result := result + lsub(n.sons[L-2]) + 2; - if n.sons[L-1] <> nil then - result := result + lsub(n.sons[L-1]) + 3; - end; - nkVarTuple: result := lcomma(n, 0, -3) + length('() = ') + lsub(lastSon(n)); - nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n); - nkChckRange64: result := length('chckRange64') + 2 + lcomma(n); - nkChckRange: result := length('chckRange') + 2 + lcomma(n); - - nkObjDownConv, nkObjUpConv, - nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin - result := 2; - if sonsLen(n) >= 1 then - result := result + lsub(n.sons[0]); - result := result + lcomma(n, 1); - end; - nkExprColonExpr: result := lsons(n) + 2; - nkInfix: result := lsons(n) + 2; - nkPrefix: result := lsons(n) + 1; - nkPostfix: result := lsons(n); - nkCallStrLit: result := lsons(n); - nkPragmaExpr: result := lsub(n.sons[0])+lcomma(n, 1); - nkRange: result := lsons(n) + 2; - nkDerefExpr: result := lsub(n.sons[0])+2; - nkAccQuoted: result := lsub(n.sons[0]) + 2; - - nkIfExpr: result := lsub(n.sons[0].sons[0])+lsub(n.sons[0].sons[1]) - + lsons(n, 1) + length('if_:_'); - nkElifExpr: result := lsons(n) + length('_elif_:_'); - nkElseExpr: result := lsub(n.sons[0])+ length('_else:_'); - - // type descriptions - nkTypeOfExpr: result := lsub(n.sons[0])+length('type_'); - nkRefTy: result := lsub(n.sons[0])+length('ref_'); - nkPtrTy: result := lsub(n.sons[0])+length('ptr_'); - nkVarTy: result := lsub(n.sons[0])+length('var_'); - nkDistinctTy: result := lsub(n.sons[0])+length('Distinct_'); - nkTypeDef: result := lsons(n)+3; - nkOfInherit: result := lsub(n.sons[0])+length('of_'); - nkProcTy: result := lsons(n)+length('proc_'); - nkEnumTy: result := lsub(n.sons[0])+lcomma(n,1)+length('enum_'); - nkEnumFieldDef: result := lsons(n)+3; - - nkVarSection: if sonsLen(n) > 1 then result := maxLineLen+1 - else result := lsons(n) + length('var_'); - nkReturnStmt: result := lsub(n.sons[0])+length('return_'); - nkRaiseStmt: result := lsub(n.sons[0])+length('raise_'); - nkYieldStmt: result := lsub(n.sons[0])+length('yield_'); - nkDiscardStmt: result := lsub(n.sons[0])+length('discard_'); - nkBreakStmt: result := lsub(n.sons[0])+length('break_'); - nkContinueStmt: result := lsub(n.sons[0])+length('continue_'); - nkPragma: result := lcomma(n) + 4; - nkCommentStmt: result := length(n.comment); - - nkOfBranch: result := lcomma(n, 0, -2) + lsub(lastSon(n)) - + length('of_:_'); - nkElifBranch: result := lsons(n)+length('elif_:_'); - nkElse: result := lsub(n.sons[0]) + length('else:_'); - nkFinally: result := lsub(n.sons[0]) + length('finally:_'); - nkGenericParams: result := lcomma(n) + 2; - nkFormalParams: begin - result := lcomma(n, 1) + 2; - if n.sons[0] <> nil then result := result + lsub(n.sons[0]) + 2 - end; - nkExceptBranch: result := lcomma(n, 0, -2) + lsub(lastSon(n)) - + length('except_:_'); - else result := maxLineLen+1 - end -end; - -function fits(const g: TSrcGen; x: int): bool; -begin - result := x + g.lineLen <= maxLineLen -end; - -// ------------------------- render part -------------------------------------- - -type - TSubFlag = (rfLongMode, rfNoIndent, rfInConstExpr); - TSubFlags = set of TSubFlag; - TContext = record{@tuple} - spacing: int; - flags: TSubFlags; - end; - -const - emptyContext: TContext = (spacing: 0; flags: {@set}[]); - -procedure initContext(out c: TContext); -begin - c.spacing := 0; - c.flags := {@set}[]; -end; - -procedure gsub(var g: TSrcGen; n: PNode; const c: TContext); overload; forward; - -procedure gsub(var g: TSrcGen; n: PNode); overload; -var - c: TContext; -begin - initContext(c); - gsub(g, n, c); -end; - -function hasCom(n: PNode): bool; -var - i: int; -begin - result := false; - if n = nil then exit; - if n.comment <> snil then begin result := true; exit end; - case n.kind of - nkEmpty..nkNilLit: begin end; - else begin - for i := 0 to sonsLen(n)-1 do - if hasCom(n.sons[i]) then begin - result := true; exit - end - end - end -end; - -procedure putWithSpace(var g: TSrcGen; kind: TTokType; const s: string); -begin - put(g, kind, s); - put(g, tkSpaces, Space); -end; - -procedure gcommaAux(var g: TSrcGen; n: PNode; ind: int; - start: int = 0; theEnd: int = -1); -var - i, sublen: int; - c: bool; -begin - for i := start to sonsLen(n)+theEnd do begin - c := i < sonsLen(n)+theEnd; - sublen := lsub(n.sons[i])+ord(c); - if not fits(g, sublen) and (ind+sublen < maxLineLen) then optNL(g, ind); - gsub(g, n.sons[i]); - if c then begin - putWithSpace(g, tkComma, ','+''); - if hasCom(n.sons[i]) then begin - gcoms(g); - optNL(g, ind); - end - end - end -end; - -procedure gcomma(var g: TSrcGen; n: PNode; const c: TContext; - start: int = 0; theEnd: int = -1); overload; -var - ind: int; -begin - if rfInConstExpr in c.flags then - ind := g.indent + indentWidth - else begin - ind := g.lineLen; - if ind > maxLineLen div 2 then ind := g.indent + longIndentWid - end; - gcommaAux(g, n, ind, start, theEnd); -end; - -procedure gcomma(var g: TSrcGen; n: PNode; - start: int = 0; theEnd: int = -1); overload; -var - ind: int; -begin - ind := g.lineLen; - if ind > maxLineLen div 2 then ind := g.indent + longIndentWid; - gcommaAux(g, n, ind, start, theEnd); -end; - -procedure gsons(var g: TSrcGen; n: PNode; const c: TContext; - start: int = 0; theEnd: int = -1); -var - i: int; -begin - for i := start to sonsLen(n)+theEnd do begin - gsub(g, n.sons[i], c); - end -end; - -procedure gsection(var g: TSrcGen; n: PNode; const c: TContext; kind: TTokType; - const k: string); -var - i: int; -begin - if sonsLen(n) = 0 then exit; // empty var sections are possible - putWithSpace(g, kind, k); - gcoms(g); - indentNL(g); - for i := 0 to sonsLen(n)-1 do begin - optNL(g); - gsub(g, n.sons[i], c); - gcoms(g); - end; - dedent(g); -end; - - -function longMode(n: PNode; start: int = 0; theEnd: int = -1): bool; -var - i: int; -begin - result := n.comment <> snil; - if not result then begin - // check further - for i := start to sonsLen(n)+theEnd do begin - if (lsub(n.sons[i]) > maxLineLen) then begin - result := true; break end; - end - end -end; - -procedure gstmts(var g: TSrcGen; n: PNode; const c: TContext); -var - i: int; -begin - if n = nil then exit; - if (n.kind = nkStmtList) or (n.kind = nkStmtListExpr) then begin - indentNL(g); - for i := 0 to sonsLen(n)-1 do begin - optNL(g); - gsub(g, n.sons[i]); - gcoms(g); - end; - dedent(g); - end - else begin - if rfLongMode in c.flags then indentNL(g); - gsub(g, n); - gcoms(g); - optNL(g); - if rfLongMode in c.flags then dedent(g); - end -end; - -procedure gif(var g: TSrcGen; n: PNode); -var - c: TContext; - i, len: int; -begin - gsub(g, n.sons[0].sons[0]); - initContext(c); - putWithSpace(g, tkColon, ':'+''); - if longMode(n) or (lsub(n.sons[0].sons[1])+g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcoms(g); // a good place for comments - gstmts(g, n.sons[0].sons[1], c); - len := sonsLen(n); - for i := 1 to len-1 do begin - optNL(g); - gsub(g, n.sons[i], c) - end; -end; - -procedure gwhile(var g: TSrcGen; n: PNode); -var - c: TContext; -begin - putWithSpace(g, tkWhile, 'while'); - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - initContext(c); - if longMode(n) or (lsub(n.sons[1])+g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcoms(g); // a good place for comments - gstmts(g, n.sons[1], c); -end; - -procedure gtry(var g: TSrcGen; n: PNode); -var - c: TContext; -begin - put(g, tkTry, 'try'); - putWithSpace(g, tkColon, ':'+''); - initContext(c); - if longMode(n) or (lsub(n.sons[0])+g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcoms(g); // a good place for comments - gstmts(g, n.sons[0], c); - gsons(g, n, c, 1); -end; - -procedure gfor(var g: TSrcGen; n: PNode); -var - c: TContext; - len: int; -begin - len := sonsLen(n); - putWithSpace(g, tkFor, 'for'); - initContext(c); - if longMode(n) - or (lsub(n.sons[len-1]) - + lsub(n.sons[len-2]) + 6 + g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcomma(g, n, c, 0, -3); - put(g, tkSpaces, Space); - putWithSpace(g, tkIn, 'in'); - gsub(g, n.sons[len-2], c); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, n.sons[len-1], c); -end; - -procedure gmacro(var g: TSrcGen; n: PNode); -var - c: TContext; -begin - initContext(c); - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - if longMode(n) or (lsub(n.sons[1])+g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcoms(g); - gsons(g, n, c, 1); -end; - -procedure gcase(var g: TSrcGen; n: PNode); -var - c: TContext; - len, last: int; -begin - initContext(c); - len := sonsLen(n); - if n.sons[len-1].kind = nkElse then last := -2 - else last := -1; - if longMode(n, 0, last) then include(c.flags, rfLongMode); - putWithSpace(g, tkCase, 'case'); - gsub(g, n.sons[0]); - gcoms(g); - optNL(g); - gsons(g, n, c, 1, last); - if last = -2 then begin - initContext(c); - if longMode(n.sons[len-1]) then include(c.flags, rfLongMode); - gsub(g, n.sons[len-1], c); - end -end; - -procedure gproc(var g: TSrcGen; n: PNode); -var - c: TContext; -begin - gsub(g, n.sons[0]); - gsub(g, n.sons[1]); - gsub(g, n.sons[2]); - gsub(g, n.sons[3]); - if not (renderNoBody in g.flags) then begin - if n.sons[4] <> nil then begin - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - indentNL(g); - gcoms(g); - dedent(g); - initContext(c); - gstmts(g, n.sons[4], c); - putNL(g); - end - else begin - indentNL(g); - gcoms(g); - dedent(g); - end - end; -end; - -procedure gblock(var g: TSrcGen; n: PNode); -var - c: TContext; -begin - initContext(c); - putWithSpace(g, tkBlock, 'block'); - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - if longMode(n) or (lsub(n.sons[1])+g.lineLen > maxLineLen) then - include(c.flags, rfLongMode); - gcoms(g); - gstmts(g, n.sons[1], c); -end; - -procedure gasm(var g: TSrcGen; n: PNode); -begin - putWithSpace(g, tkAsm, 'asm'); - gsub(g, n.sons[0]); - gcoms(g); - gsub(g, n.sons[1]); -end; - -procedure gident(var g: TSrcGen; n: PNode); -var - s: string; - t: TTokType; -begin - s := atom(n); - if (s[strStart] in scanner.SymChars) then begin - if (n.kind = nkIdent) then begin - if (n.ident.id < ord(tokKeywordLow)-ord(tkSymbol)) or - (n.ident.id > ord(tokKeywordHigh)-ord(tkSymbol)) then - t := tkSymbol - else - t := TTokType(n.ident.id+ord(tkSymbol)) - end - else - t := tkSymbol; - end - else - t := tkOpr; - put(g, t, s); - if (n.kind = nkSym) and (renderIds in g.flags) then - put(g, tkIntLit, toString(n.sym.id)); -end; - -procedure gsub(var g: TSrcGen; n: PNode; const c: TContext); -var - L, i: int; - a: TContext; -begin - if n = nil then exit; - if n.comment <> snil then pushCom(g, n); - case n.kind of - // atoms: - nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal); - nkEmpty, nkType: put(g, tkInvalid, atom(n)); - nkSym, nkIdent: gident(g, n); - nkIntLit: put(g, tkIntLit, atom(n)); - nkInt8Lit: put(g, tkInt8Lit, atom(n)); - nkInt16Lit: put(g, tkInt16Lit, atom(n)); - nkInt32Lit: put(g, tkInt32Lit, atom(n)); - nkInt64Lit: put(g, tkInt64Lit, atom(n)); - nkFloatLit: put(g, tkFloatLit, atom(n)); - nkFloat32Lit: put(g, tkFloat32Lit, atom(n)); - nkFloat64Lit: put(g, tkFloat64Lit, atom(n)); - nkStrLit: put(g, tkStrLit, atom(n)); - nkRStrLit: put(g, tkRStrLit, atom(n)); - nkCharLit: put(g, tkCharLit, atom(n)); - nkNilLit: put(g, tkNil, atom(n)); - // complex expressions - nkCall, nkConv, nkDotCall: begin - if sonsLen(n) >= 1 then - gsub(g, n.sons[0]); - put(g, tkParLe, '('+''); - gcomma(g, n, 1); - put(g, tkParRi, ')'+''); - end; - nkCallStrLit: begin - gsub(g, n.sons[0]); - if n.sons[1].kind = nkRStrLit then - put(g, tkRStrLit, '"' + n.sons[1].strVal + '"') - else - gsub(g, n.sons[0]); - end; - nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: begin - gsub(g, n.sons[0]); - end; - nkCast: begin - put(g, tkCast, 'cast'); - put(g, tkBracketLe, '['+''); - gsub(g, n.sons[0]); - put(g, tkBracketRi, ']'+''); - put(g, tkParLe, '('+''); - gsub(g, n.sons[1]); - put(g, tkParRi, ')'+''); - end; - nkAddr: begin - put(g, tkAddr, 'addr'); - put(g, tkParLe, '('+''); - gsub(g, n.sons[0]); - put(g, tkParRi, ')'+''); - end; - nkBracketExpr: begin - gsub(g, n.sons[0]); - put(g, tkBracketLe, '['+''); - gcomma(g, n, 1); - put(g, tkBracketRi, ']'+''); - end; - nkPragmaExpr: begin - gsub(g, n.sons[0]); - gcomma(g, n, 1); - end; - nkCommand: begin - gsub(g, n.sons[0]); - put(g, tkSpaces, space); - gcomma(g, n, 1); - end; - nkExprEqExpr, nkAsgn, nkFastAsgn: begin - gsub(g, n.sons[0]); - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - gsub(g, n.sons[1]); - end; - nkChckRangeF: begin - put(g, tkSymbol, 'chckRangeF'); - put(g, tkParLe, '('+''); - gcomma(g, n); - put(g, tkParRi, ')'+''); - end; - nkChckRange64: begin - put(g, tkSymbol, 'chckRange64'); - put(g, tkParLe, '('+''); - gcomma(g, n); - put(g, tkParRi, ')'+''); - end; - nkChckRange: begin - put(g, tkSymbol, 'chckRange'); - put(g, tkParLe, '('+''); - gcomma(g, n); - put(g, tkParRi, ')'+''); - end; - nkObjDownConv, nkObjUpConv, - nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin - if sonsLen(n) >= 1 then - gsub(g, n.sons[0]); - put(g, tkParLe, '('+''); - gcomma(g, n, 1); - put(g, tkParRi, ')'+''); - end; - nkSymChoice: begin - put(g, tkParLe, '('+''); - for i := 0 to sonsLen(n)-1 do begin - if i > 0 then put(g, tkOpr, '|'+''); - gsub(g, n.sons[i], c); - end; - put(g, tkParRi, ')'+''); - end; - nkPar: begin - put(g, tkParLe, '('+''); - gcomma(g, n, c); - put(g, tkParRi, ')'+''); - end; - nkCurly: begin - put(g, tkCurlyLe, '{'+''); - gcomma(g, n, c); - put(g, tkCurlyRi, '}'+''); - end; - nkBracket: begin - put(g, tkBracketLe, '['+''); - gcomma(g, n, c); - put(g, tkBracketRi, ']'+''); - end; - nkDotExpr: begin - gsub(g, n.sons[0]); - put(g, tkDot, '.'+''); - gsub(g, n.sons[1]); - end; - nkBind: begin - putWithSpace(g, tkBind, 'bind'); - gsub(g, n.sons[0]); - end; - nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]); - nkLambda: begin - assert(n.sons[genericParamsPos] = nil); - putWithSpace(g, tkLambda, 'lambda'); - gsub(g, n.sons[paramsPos]); - gsub(g, n.sons[pragmasPos]); - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - gsub(g, n.sons[codePos]); - end; - nkConstDef, nkIdentDefs: begin - gcomma(g, n, 0, -3); - L := sonsLen(n); - if n.sons[L-2] <> nil then begin - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[L-2]) - end; - if n.sons[L-1] <> nil then begin - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - gsub(g, n.sons[L-1], c) - end; - end; - nkVarTuple: begin - put(g, tkParLe, '('+''); - gcomma(g, n, 0, -3); - put(g, tkParRi, ')'+''); - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - gsub(g, lastSon(n), c); - end; - nkExprColonExpr: begin - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[1]); - end; - nkInfix: begin - gsub(g, n.sons[1]); - put(g, tkSpaces, Space); - gsub(g, n.sons[0]); // binary operator - if not fits(g, lsub(n.sons[2])+ lsub(n.sons[0]) + 1) then - optNL(g, g.indent+longIndentWid) - else put(g, tkSpaces, Space); - gsub(g, n.sons[2]); - end; - nkPrefix: begin - gsub(g, n.sons[0]); - put(g, tkSpaces, space); - gsub(g, n.sons[1]); - end; - nkPostfix: begin - gsub(g, n.sons[1]); - gsub(g, n.sons[0]); - end; - nkRange: begin - gsub(g, n.sons[0]); - put(g, tkDotDot, '..'); - gsub(g, n.sons[1]); - end; - nkDerefExpr: begin - gsub(g, n.sons[0]); - putWithSpace(g, tkHat, '^'+''); - // unfortunately this requires a space, because ^. would be - // only one operator - end; - nkAccQuoted: begin - put(g, tkAccent, '`'+''); - gsub(g, n.sons[0]); - put(g, tkAccent, '`'+''); - end; - nkIfExpr: begin - putWithSpace(g, tkIf, 'if'); - gsub(g, n.sons[0].sons[0]); - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[0].sons[1]); - gsons(g, n, emptyContext, 1); - end; - nkElifExpr: begin - putWithSpace(g, tkElif, ' elif'); - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[1]); - end; - nkElseExpr: begin - put(g, tkElse, ' else'); - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[0]); - end; - - nkTypeOfExpr: begin - putWithSpace(g, tkType, 'type'); - gsub(g, n.sons[0]); - end; - nkRefTy: begin - putWithSpace(g, tkRef, 'ref'); - gsub(g, n.sons[0]); - end; - nkPtrTy: begin - putWithSpace(g, tkPtr, 'ptr'); - gsub(g, n.sons[0]); - end; - nkVarTy: begin - putWithSpace(g, tkVar, 'var'); - gsub(g, n.sons[0]); - end; - nkDistinctTy: begin - putWithSpace(g, tkDistinct, 'distinct'); - gsub(g, n.sons[0]); - end; - nkTypeDef: begin - gsub(g, n.sons[0]); - gsub(g, n.sons[1]); - put(g, tkSpaces, Space); - if n.sons[2] <> nil then begin - putWithSpace(g, tkEquals, '='+''); - gsub(g, n.sons[2]); - end - end; - nkObjectTy: begin - putWithSpace(g, tkObject, 'object'); - gsub(g, n.sons[0]); - gsub(g, n.sons[1]); - gcoms(g); - gsub(g, n.sons[2]); - end; - nkRecList: begin - indentNL(g); - for i := 0 to sonsLen(n)-1 do begin - optNL(g); - gsub(g, n.sons[i], c); - gcoms(g); - end; - dedent(g); - putNL(g); - end; - nkOfInherit: begin - putWithSpace(g, tkOf, 'of'); - gsub(g, n.sons[0]); - end; - nkProcTy: begin - putWithSpace(g, tkProc, 'proc'); - gsub(g, n.sons[0]); - gsub(g, n.sons[1]); - end; - nkEnumTy: begin - putWithSpace(g, tkEnum, 'enum'); - gsub(g, n.sons[0]); - gcoms(g); - indentNL(g); - gcommaAux(g, n, g.indent, 1); - gcoms(g); // BUGFIX: comment for the last enum field - dedent(g); - end; - nkEnumFieldDef: begin - gsub(g, n.sons[0]); - put(g, tkSpaces, Space); - putWithSpace(g, tkEquals, '='+''); - gsub(g, n.sons[1]); - end; - nkStmtList, nkStmtListExpr: gstmts(g, n, emptyContext); - nkIfStmt: begin - putWithSpace(g, tkIf, 'if'); - gif(g, n); - end; - nkWhenStmt, nkRecWhen: begin - putWithSpace(g, tkWhen, 'when'); - gif(g, n); - end; - nkWhileStmt: gwhile(g, n); - nkCaseStmt, nkRecCase: gcase(g, n); - nkMacroStmt: gmacro(g, n); - nkTryStmt: gtry(g, n); - nkForStmt: gfor(g, n); - nkBlockStmt, nkBlockExpr: gblock(g, n); - nkAsmStmt: gasm(g, n); - nkProcDef: begin - putWithSpace(g, tkProc, 'proc'); - gproc(g, n); - end; - nkMethodDef: begin - putWithSpace(g, tkMethod, 'method'); - gproc(g, n); - end; - nkIteratorDef: begin - putWithSpace(g, tkIterator, 'iterator'); - gproc(g, n); - end; - nkMacroDef: begin - putWithSpace(g, tkMacro, 'macro'); - gproc(g, n); - end; - nkTemplateDef: begin - putWithSpace(g, tkTemplate, 'template'); - gproc(g, n); - end; - nkTypeSection: gsection(g, n, emptyContext, tkType, 'type'); - nkConstSection: begin - initContext(a); - include(a.flags, rfInConstExpr); - gsection(g, n, a, tkConst, 'const') - end; - nkVarSection: begin - L := sonsLen(n); - if L = 0 then exit; - putWithSpace(g, tkVar, 'var'); - if L > 1 then begin - gcoms(g); - indentNL(g); - for i := 0 to L-1 do begin - optNL(g); - gsub(g, n.sons[i]); - gcoms(g); - end; - dedent(g); - end - else - gsub(g, n.sons[0]); - end; - nkReturnStmt: begin - putWithSpace(g, tkReturn, 'return'); - gsub(g, n.sons[0]); - end; - nkRaiseStmt: begin - putWithSpace(g, tkRaise, 'raise'); - gsub(g, n.sons[0]); - end; - nkYieldStmt: begin - putWithSpace(g, tkYield, 'yield'); - gsub(g, n.sons[0]); - end; - nkDiscardStmt: begin - putWithSpace(g, tkDiscard, 'discard'); - gsub(g, n.sons[0]); - end; - nkBreakStmt: begin - putWithSpace(g, tkBreak, 'break'); - gsub(g, n.sons[0]); - end; - nkContinueStmt: begin - putWithSpace(g, tkContinue, 'continue'); - gsub(g, n.sons[0]); - end; - nkPragma: begin - if not (renderNoPragmas in g.flags) then begin - put(g, tkCurlyDotLe, '{.'); - gcomma(g, n, emptyContext); - put(g, tkCurlyDotRi, '.}') - end; - end; - nkImportStmt: begin - putWithSpace(g, tkImport, 'import'); - gcoms(g); - indentNL(g); - gcommaAux(g, n, g.indent); - dedent(g); - putNL(g); - end; - nkFromStmt: begin - putWithSpace(g, tkFrom, 'from'); - gsub(g, n.sons[0]); - put(g, tkSpaces, Space); - putWithSpace(g, tkImport, 'import'); - gcomma(g, n, emptyContext, 1); - putNL(g); - end; - nkIncludeStmt: begin - putWithSpace(g, tkInclude, 'include'); - gcoms(g); - indentNL(g); - gcommaAux(g, n, g.indent); - dedent(g); - putNL(g); - end; - nkCommentStmt: begin - gcoms(g); - optNL(g); - end; - nkOfBranch: begin - optNL(g); - putWithSpace(g, tkOf, 'of'); - gcomma(g, n, c, 0, -2); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, lastSon(n), c); - end; - nkElifBranch: begin - optNL(g); - putWithSpace(g, tkElif, 'elif'); - gsub(g, n.sons[0]); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, n.sons[1], c) - end; - nkElse: begin - optNL(g); - put(g, tkElse, 'else'); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, n.sons[0], c) - end; - nkFinally: begin - optNL(g); - put(g, tkFinally, 'finally'); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, n.sons[0], c) - end; - nkExceptBranch: begin - optNL(g); - putWithSpace(g, tkExcept, 'except'); - gcomma(g, n, 0, -2); - putWithSpace(g, tkColon, ':'+''); - gcoms(g); - gstmts(g, lastSon(n), c) - end; - nkGenericParams: begin - put(g, tkBracketLe, '['+''); - gcomma(g, n); - put(g, tkBracketRi, ']'+''); - end; - nkFormalParams: begin - put(g, tkParLe, '('+''); - gcomma(g, n, 1); - put(g, tkParRi, ')'+''); - if n.sons[0] <> nil then begin - putWithSpace(g, tkColon, ':'+''); - gsub(g, n.sons[0]); - end; - // XXX: gcomma(g, n, 1, -2); - end; - nkTupleTy: begin - put(g, tkTuple, 'tuple'); - put(g, tkBracketLe, '['+''); - gcomma(g, n); - put(g, tkBracketRi, ']'+''); - end; - else begin - //nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall: begin - InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')') - end - end -end; - -function renderTree(n: PNode; renderFlags: TRenderFlags = {@set}[]): string; -var - g: TSrcGen; -begin - initSrcGen(g, renderFlags); - gsub(g, n); - result := g.buf -end; - -procedure renderModule(n: PNode; const filename: string; - renderFlags: TRenderFlags = {@set}[]); -var - i: int; - f: tTextFile; - g: TSrcGen; -begin - initSrcGen(g, renderFlags); - for i := 0 to sonsLen(n)-1 do begin - gsub(g, n.sons[i]); - optNL(g); - if n.sons[i] <> nil then - case n.sons[i].kind of - nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: - putNL(g); - else begin end - end - end; - gcoms(g); - if OpenFile(f, filename, fmWrite) then begin - nimWrite(f, g.buf); - nimCloseFile(f); - end; -end; - -procedure initTokRender(var r: TSrcGen; n: PNode; - renderFlags: TRenderFlags = {@set}[]); -begin - initSrcGen(r, renderFlags); - gsub(r, n); -end; - -procedure getNextTok(var r: TSrcGen; var kind: TTokType; var literal: string); -var - len: int; -begin - if r.idx < length(r.tokens) then begin - kind := r.tokens[r.idx].kind; - len := r.tokens[r.idx].len; - literal := ncopy(r.buf, r.pos+strStart, r.pos+strStart+len-1); - inc(r.pos, len); - inc(r.idx); - end - else - kind := tkEof; -end; - -end. |