mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-02 03:02:31 +00:00
1459 lines
37 KiB
ObjectPascal
1459 lines
37 KiB
ObjectPascal
//
|
|
//
|
|
// 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.
|