diff options
author | Araq <rumpf_a@web.de> | 2011-04-12 01:13:42 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-04-12 01:13:42 +0200 |
commit | cd292568d775d55d9abb51e962882ecda12c03a9 (patch) | |
tree | 85451f0e1f17dc0463350915f12bdd0a82a73455 /nim/transf.pas | |
parent | 46c41e43690cba9bc1caff6a994bb6915df8a1b7 (diff) | |
download | Nim-cd292568d775d55d9abb51e962882ecda12c03a9.tar.gz |
big repo cleanup
Diffstat (limited to 'nim/transf.pas')
-rwxr-xr-x | nim/transf.pas | 964 |
1 files changed, 0 insertions, 964 deletions
diff --git a/nim/transf.pas b/nim/transf.pas deleted file mode 100755 index a0f07d51d..000000000 --- a/nim/transf.pas +++ /dev/null @@ -1,964 +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 transf; - -// This module implements the transformator. It transforms the syntax tree -// to ease the work of the code generators. Does some transformations: -// -// * inlines iterators -// * inlines constants -// * performes contant folding -// * introduces nkHiddenDeref, nkHiddenSubConv, etc. -// * introduces method dispatchers - -interface - -{$include 'config.inc'} - -uses - sysutils, nsystem, charsets, strutils, - lists, options, ast, astalgo, trees, treetab, evals, - msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys, cgmeth; - -const - genPrefix = ':tmp'; // prefix for generated names - -function transfPass(): TPass; - -implementation - -type - PTransCon = ^TTransCon; - TTransCon = record // part of TContext; stackable - mapping: TIdNodeTable; // mapping from symbols to nodes - owner: PSym; // current owner - forStmt: PNode; // current for stmt - next: PTransCon; // for stacking - end; - - TTransfContext = object(passes.TPassContext) - module: PSym; - transCon: PTransCon; // top of a TransCon stack - end; - PTransf = ^TTransfContext; - -function newTransCon(): PTransCon; -begin - new(result); -{@ignore} - fillChar(result^, sizeof(result^), 0); -{@emit} - initIdNodeTable(result.mapping); -end; - -procedure pushTransCon(c: PTransf; t: PTransCon); -begin - t.next := c.transCon; - c.transCon := t; -end; - -procedure popTransCon(c: PTransf); -begin - if (c.transCon = nil) then InternalError('popTransCon'); - c.transCon := c.transCon.next; -end; - -// ------------ helpers ----------------------------------------------------- - -function getCurrOwner(c: PTransf): PSym; -begin - if c.transCon <> nil then result := c.transCon.owner - else result := c.module; -end; - -function newTemp(c: PTransf; typ: PType; const info: TLineInfo): PSym; -begin - result := newSym(skTemp, getIdent(genPrefix), getCurrOwner(c)); - result.info := info; - result.typ := skipTypes(typ, {@set}[tyGenericInst]); - include(result.flags, sfFromGeneric); -end; - -// -------------------------------------------------------------------------- - -function transform(c: PTransf; n: PNode): PNode; forward; - -(* - -Transforming iterators into non-inlined versions is pretty hard, but -unavoidable for not bloating the code too much. If we had direct access to -the program counter, things'd be much easier. -:: - - iterator items(a: string): char = - var i = 0 - while i < length(a): - yield a[i] - inc(i) - - for ch in items("hello world"): # `ch` is an iteration variable - echo(ch) - -Should be transformed into:: - - type - TItemsClosure = record - i: int - state: int - proc items(a: string, c: var TItemsClosure): char = - case c.state - of 0: goto L0 # very difficult without goto! - of 1: goto L1 # can be implemented by GCC's computed gotos - - block L0: - c.i = 0 - while c.i < length(a): - c.state = 1 - return a[i] - block L1: inc(c.i) - -More efficient, but not implementable:: - - type - TItemsClosure = record - i: int - pc: pointer - - proc items(a: string, c: var TItemsClosure): char = - goto c.pc - c.i = 0 - while c.i < length(a): - c.pc = label1 - return a[i] - label1: inc(c.i) -*) - -function newAsgnStmt(c: PTransf; le, ri: PNode): PNode; -begin - result := newNodeI(nkFastAsgn, ri.info); - addSon(result, le); - addSon(result, ri); -end; - -function transformSym(c: PTransf; n: PNode): PNode; -var - tc: PTransCon; - b: PNode; -begin - if (n.kind <> nkSym) then internalError(n.info, 'transformSym'); - tc := c.transCon; - if sfBorrow in n.sym.flags then begin - // simply exchange the symbol: - b := n.sym.ast.sons[codePos]; - if b.kind <> nkSym then - internalError(n.info, 'wrong AST for borrowed symbol'); - b := newSymNode(b.sym); - b.info := n.info; - end - else - b := n; - //writeln('transformSym', n.sym.id : 5); - while tc <> nil do begin - result := IdNodeTableGet(tc.mapping, b.sym); - if result <> nil then exit; - //write('not found in: '); - //writeIdNodeTable(tc.mapping); - tc := tc.next - end; - result := b; - case b.sym.kind of - skConst, skEnumField: begin // BUGFIX: skEnumField was missing - if not (skipTypes(b.sym.typ, abstractInst).kind in ConstantDataTypes) then begin - result := getConstExpr(c.module, b); - if result = nil then InternalError(b.info, 'transformSym: const'); - end - end - else begin end - end -end; - -procedure transformContinueAux(c: PTransf; n: PNode; labl: PSym; - var counter: int); -var - i: int; -begin - if n = nil then exit; - case n.kind of - nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: begin end; - nkContinueStmt: begin - n.kind := nkBreakStmt; - addSon(n, newSymNode(labl)); - inc(counter); - end; - else begin - for i := 0 to sonsLen(n)-1 do - transformContinueAux(c, n.sons[i], labl, counter); - end - end -end; - -function transformContinue(c: PTransf; n: PNode): PNode; -// we transform the continue statement into a block statement -var - i, counter: int; - x: PNode; - labl: PSym; -begin - result := n; - for i := 0 to sonsLen(n)-1 do - result.sons[i] := transform(c, n.sons[i]); - counter := 0; - labl := newSym(skLabel, nil, getCurrOwner(c)); - labl.name := getIdent(genPrefix +{&} ToString(labl.id)); - labl.info := result.info; - transformContinueAux(c, result, labl, counter); - if counter > 0 then begin - x := newNodeI(nkBlockStmt, result.info); - addSon(x, newSymNode(labl)); - addSon(x, result); - result := x - end -end; - -function skipConv(n: PNode): PNode; -begin - case n.kind of - nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, - nkChckRangeF, nkChckRange64: - result := n.sons[0]; - nkHiddenStdConv, nkHiddenSubConv, nkConv: result := n.sons[1]; - else result := n - end -end; - -function newTupleAccess(tup: PNode; i: int): PNode; -var - lit: PNode; -begin - result := newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i]); - addSon(result, copyTree(tup)); - lit := newNodeIT(nkIntLit, tup.info, getSysType(tyInt)); - lit.intVal := i; - addSon(result, lit); -end; - -procedure unpackTuple(c: PTransf; n, father: PNode); -var - i: int; -begin - // XXX: BUG: what if `n` is an expression with side-effects? - for i := 0 to sonsLen(n)-1 do begin - addSon(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], - transform(c, newTupleAccess(n, i)))); - end -end; - -function transformYield(c: PTransf; n: PNode): PNode; -var - e: PNode; - i: int; -begin - result := newNodeI(nkStmtList, n.info); - e := n.sons[0]; - if skipTypes(e.typ, {@set}[tyGenericInst]).kind = tyTuple then begin - e := skipConv(e); - if e.kind = nkPar then begin - for i := 0 to sonsLen(e)-1 do begin - addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], - transform(c, copyTree(e.sons[i])))); - end - end - else - unpackTuple(c, e, result); - end - else begin - e := transform(c, copyTree(e)); - addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], e)); - end; - // add body of the for loop: - addSon(result, transform(c, lastSon(c.transCon.forStmt))); -end; - -function inlineIter(c: PTransf; n: PNode): PNode; -var - i, j, L: int; - it: PNode; - newVar: PSym; -begin - result := n; - if n = nil then exit; - case n.kind of - nkEmpty..nkNilLit: begin - result := transform(c, copyTree(n)); - end; - nkYieldStmt: result := transformYield(c, n); - nkVarSection: begin - result := copyTree(n); - for i := 0 to sonsLen(result)-1 do begin - it := result.sons[i]; - if it.kind = nkCommentStmt then continue; - if it.kind = nkIdentDefs then begin - if (it.sons[0].kind <> nkSym) then - InternalError(it.info, 'inlineIter'); - newVar := copySym(it.sons[0].sym); - include(newVar.flags, sfFromGeneric); - // fixes a strange bug for rodgen: - //include(it.sons[0].sym.flags, sfFromGeneric); - newVar.owner := getCurrOwner(c); - IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar)); - it.sons[0] := newSymNode(newVar); - it.sons[2] := transform(c, it.sons[2]); - end - else begin - if it.kind <> nkVarTuple then - InternalError(it.info, 'inlineIter: not nkVarTuple'); - L := sonsLen(it); - for j := 0 to L-3 do begin - newVar := copySym(it.sons[j].sym); - include(newVar.flags, sfFromGeneric); - newVar.owner := getCurrOwner(c); - IdNodeTablePut(c.transCon.mapping, it.sons[j].sym, - newSymNode(newVar)); - it.sons[j] := newSymNode(newVar); - end; - assert(it.sons[L-2] = nil); - it.sons[L-1] := transform(c, it.sons[L-1]); - end - end - end - else begin - result := copyNode(n); - for i := 0 to sonsLen(n)-1 do addSon(result, inlineIter(c, n.sons[i])); - result := transform(c, result); - end - end -end; - -procedure addVar(father, v: PNode); -var - vpart: PNode; -begin - vpart := newNodeI(nkIdentDefs, v.info); - addSon(vpart, v); - addSon(vpart, nil); - addSon(vpart, nil); - addSon(father, vpart); -end; - -function transformAddrDeref(c: PTransf; n: PNode; a, b: TNodeKind): PNode; -var - m: PNode; -begin - case n.sons[0].kind of - nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, - nkChckRangeF, nkChckRange64: begin - m := n.sons[0].sons[0]; - if (m.kind = a) or (m.kind = b) then begin - // addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x) - n.sons[0].sons[0] := m.sons[0]; - result := transform(c, n.sons[0]); - exit - end - end; - nkHiddenStdConv, nkHiddenSubConv, nkConv: begin - m := n.sons[0].sons[1]; - if (m.kind = a) or (m.kind = b) then begin - // addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) - n.sons[0].sons[1] := m.sons[0]; - result := transform(c, n.sons[0]); - exit - end - end; - else begin - if (n.sons[0].kind = a) or (n.sons[0].kind = b) then begin - // addr ( deref ( x )) --> x - result := transform(c, n.sons[0].sons[0]); - exit - end - end - end; - n.sons[0] := transform(c, n.sons[0]); - result := n; -end; - -function transformConv(c: PTransf; n: PNode): PNode; -var - source, dest: PType; - diff: int; -begin - n.sons[1] := transform(c, n.sons[1]); - result := n; - // numeric types need range checks: - dest := skipTypes(n.typ, abstractVarRange); - source := skipTypes(n.sons[1].typ, abstractVarRange); - case dest.kind of - tyInt..tyInt64, tyEnum, tyChar, tyBool: begin - if (firstOrd(dest) <= firstOrd(source)) and - (lastOrd(source) <= lastOrd(dest)) then begin - // BUGFIX: simply leave n as it is; we need a nkConv node, - // but no range check: - result := n; - end - else begin // generate a range check: - if (dest.kind = tyInt64) or (source.kind = tyInt64) then - result := newNodeIT(nkChckRange64, n.info, n.typ) - else - result := newNodeIT(nkChckRange, n.info, n.typ); - dest := skipTypes(n.typ, abstractVar); - addSon(result, n.sons[1]); - addSon(result, newIntTypeNode(nkIntLit, firstOrd(dest), source)); - addSon(result, newIntTypeNode(nkIntLit, lastOrd(dest), source)); - end - end; - tyFloat..tyFloat128: begin - if skipTypes(n.typ, abstractVar).kind = tyRange then begin - result := newNodeIT(nkChckRangeF, n.info, n.typ); - dest := skipTypes(n.typ, abstractVar); - addSon(result, n.sons[1]); - addSon(result, copyTree(dest.n.sons[0])); - addSon(result, copyTree(dest.n.sons[1])); - end - end; - tyOpenArray: begin - result := newNodeIT(nkPassAsOpenArray, n.info, n.typ); - addSon(result, n.sons[1]); - end; - tyCString: begin - if source.kind = tyString then begin - result := newNodeIT(nkStringToCString, n.info, n.typ); - addSon(result, n.sons[1]); - end; - end; - tyString: begin - if source.kind = tyCString then begin - result := newNodeIT(nkCStringToString, n.info, n.typ); - addSon(result, n.sons[1]); - end; - end; - tyRef, tyPtr: begin - dest := skipTypes(dest, abstractPtrs); - source := skipTypes(source, abstractPtrs); - if source.kind = tyObject then begin - diff := inheritanceDiff(dest, source); - if diff < 0 then begin - result := newNodeIT(nkObjUpConv, n.info, n.typ); - addSon(result, n.sons[1]); - end - else if diff > 0 then begin - result := newNodeIT(nkObjDownConv, n.info, n.typ); - addSon(result, n.sons[1]); - end - else result := n.sons[1]; - end - end; - // conversions between different object types: - tyObject: begin - diff := inheritanceDiff(dest, source); - if diff < 0 then begin - result := newNodeIT(nkObjUpConv, n.info, n.typ); - addSon(result, n.sons[1]); - end - else if diff > 0 then begin - result := newNodeIT(nkObjDownConv, n.info, n.typ); - addSon(result, n.sons[1]); - end - else result := n.sons[1]; - end; (* - tyArray, tySeq: begin - if skipGeneric(dest - end; *) - tyGenericParam, tyOrdinal: result := n.sons[1]; - // happens sometimes for generated assignments, etc. - else begin end - end; -end; - -function skipPassAsOpenArray(n: PNode): PNode; -begin - result := n; - while result.kind = nkPassAsOpenArray do result := result.sons[0] -end; - -type - TPutArgInto = (paDirectMapping, paFastAsgn, paVarAsgn); - -function putArgInto(arg: PNode; formal: PType): TPutArgInto; -// This analyses how to treat the mapping "formal <-> arg" in an -// inline context. -var - i: int; -begin - if skipTypes(formal, abstractInst).kind = tyOpenArray then begin - result := paDirectMapping; // XXX really correct? - // what if ``arg`` has side-effects? - exit - end; - case arg.kind of - nkEmpty..nkNilLit: result := paDirectMapping; - nkPar, nkCurly, nkBracket: begin - result := paFastAsgn; - for i := 0 to sonsLen(arg)-1 do - if putArgInto(arg.sons[i], formal) <> paDirectMapping then - exit; - result := paDirectMapping; - end; - else begin - if skipTypes(formal, abstractInst).kind = tyVar then - result := paVarAsgn - else - result := paFastAsgn - end - end -end; - -function transformFor(c: PTransf; n: PNode): PNode; -// generate access statements for the parameters (unless they are constant) -// put mapping from formal parameters to actual parameters -var - i, len: int; - call, v, body, arg: PNode; - newC: PTransCon; - temp, formal: PSym; -begin - if (n.kind <> nkForStmt) then InternalError(n.info, 'transformFor'); - result := newNodeI(nkStmtList, n.info); - len := sonsLen(n); - n.sons[len-1] := transformContinue(c, n.sons[len-1]); - v := newNodeI(nkVarSection, n.info); - for i := 0 to len-3 do addVar(v, copyTree(n.sons[i])); // declare new vars - addSon(result, v); - newC := newTransCon(); - call := n.sons[len-2]; - if (call.kind <> nkCall) or (call.sons[0].kind <> nkSym) then - InternalError(call.info, 'transformFor'); - newC.owner := call.sons[0].sym; - newC.forStmt := n; - if (newC.owner.kind <> skIterator) then - InternalError(call.info, 'transformFor'); - // generate access statements for the parameters (unless they are constant) - pushTransCon(c, newC); - for i := 1 to sonsLen(call)-1 do begin - arg := skipPassAsOpenArray(transform(c, call.sons[i])); - formal := skipTypes(newC.owner.typ, abstractInst).n.sons[i].sym; - //if IdentEq(newc.Owner.name, 'items') then - // liMessage(arg.info, warnUser, 'items: ' + nodeKindToStr[arg.kind]); - case putArgInto(arg, formal.typ) of - paDirectMapping: IdNodeTablePut(newC.mapping, formal, arg); - paFastAsgn: begin - // generate a temporary and produce an assignment statement: - temp := newTemp(c, formal.typ, formal.info); - addVar(v, newSymNode(temp)); - addSon(result, newAsgnStmt(c, newSymNode(temp), arg)); - IdNodeTablePut(newC.mapping, formal, newSymNode(temp)); - end; - paVarAsgn: begin - assert(skipTypes(formal.typ, abstractInst).kind = tyVar); - InternalError(arg.info, 'not implemented: pass to var parameter'); - end; - end; - end; - body := newC.owner.ast.sons[codePos]; - pushInfoContext(n.info); - addSon(result, inlineIter(c, body)); - popInfoContext(); - popTransCon(c); -end; - -function getMagicOp(call: PNode): TMagic; -begin - if (call.sons[0].kind = nkSym) - and (call.sons[0].sym.kind in [skProc, skMethod, skConverter]) then - result := call.sons[0].sym.magic - else - result := mNone -end; - -procedure gatherVars(c: PTransf; n: PNode; var marked: TIntSet; - owner: PSym; container: PNode); -// gather used vars for closure generation -var - i: int; - s: PSym; - found: bool; -begin - if n = nil then exit; - case n.kind of - nkSym: begin - s := n.sym; - found := false; - case s.kind of - skVar: found := not (sfGlobal in s.flags); - skTemp, skForVar, skParam: found := true; - else begin end; - end; - if found and (owner.id <> s.owner.id) - and not IntSetContainsOrIncl(marked, s.id) then begin - include(s.flags, sfInClosure); - addSon(container, copyNode(n)); // DON'T make a copy of the symbol! - end - end; - nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: begin end; - else begin - for i := 0 to sonsLen(n)-1 do - gatherVars(c, n.sons[i], marked, owner, container); - end - end -end; - -(* - # example: - proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] = - result = @[] - for elem in a: - add result, f(a) - - proc addList(a: seq[int], y: int): seq[int] = - result = map(lambda (x: int): int = return x + y, a) - - should generate --> - - proc map(f: proc(x: int): int, closure: pointer, - a: seq[int]): seq[int] = - result = @[] - for elem in a: - add result, f(a, closure) - - type - PMyClosure = ref object - y: var int - - proc myLambda(x: int, closure: pointer) = - var cl = cast[PMyClosure](closure) - return x + cl.y - - proc addList(a: seq[int], y: int): seq[int] = - var - cl: PMyClosure - new(cl) - cl.y = y - result = map(myLambda, cast[pointer](cl), a) - - - or (but this is not easier and not binary compatible with C!) --> - - type - PClosure = ref object of TObject - f: proc (x: int, c: PClosure): int - - proc map(f: PClosure, a: seq[int]): seq[int] = - result = @[] - for elem in a: - add result, f.f(a, f) - - type - PMyClosure = ref object of PClosure - y: var int - - proc myLambda(x: int, cl: PMyClosure) = - return x + cl.y - - proc addList(a: seq[int], y: int): seq[int] = - var - cl: PMyClosure - new(cl) - cl.y = y - cl.f = myLambda - result = map(cl, a) -*) - -procedure addFormalParam(routine: PSym; param: PSym); -begin - addSon(routine.typ, param.typ); - addSon(routine.ast.sons[paramsPos], newSymNode(param)); -end; - -function indirectAccess(a, b: PSym): PNode; -// returns a^ .b as a node -var - x, y, deref: PNode; -begin - x := newSymNode(a); - y := newSymNode(b); - deref := newNodeI(nkDerefExpr, x.info); - deref.typ := x.typ.sons[0]; - addSon(deref, x); - result := newNodeI(nkDotExpr, x.info); - addSon(result, deref); - addSon(result, y); - result.typ := y.typ; -end; - -function transformLambda(c: PTransf; n: PNode): PNode; -var - marked: TIntSet; - closure: PNode; - s, param: PSym; - cl, p: PType; - i: int; - newC: PTransCon; -begin - result := n; - IntSetInit(marked); - if (n.sons[namePos].kind <> nkSym) then - InternalError(n.info, 'transformLambda'); - s := n.sons[namePos].sym; - closure := newNodeI(nkRecList, n.sons[codePos].info); - gatherVars(c, n.sons[codePos], marked, s, closure); - // add closure type to the param list (even if closure is empty!): - cl := newType(tyObject, s); - cl.n := closure; - addSon(cl, nil); // no super class - p := newType(tyRef, s); - addSon(p, cl); - param := newSym(skParam, getIdent(genPrefix + 'Cl'), s); - param.typ := p; - addFormalParam(s, param); - // all variables that are accessed should be accessed by the new closure - // parameter: - if sonsLen(closure) > 0 then begin - newC := newTransCon(); - for i := 0 to sonsLen(closure)-1 do begin - IdNodeTablePut(newC.mapping, closure.sons[i].sym, - indirectAccess(param, closure.sons[i].sym)) - end; - pushTransCon(c, newC); - n.sons[codePos] := transform(c, n.sons[codePos]); - popTransCon(c); - end; - // Generate code to allocate and fill the closure. This has to be done in - // the outer routine! -end; - -function transformCase(c: PTransf; n: PNode): PNode; -// removes `elif` branches of a case stmt -// adds ``else: nil`` if needed for the code generator -var - len, i, j: int; - ifs, elsen: PNode; -begin - len := sonsLen(n); - i := len-1; - if n.sons[i].kind = nkElse then dec(i); - if n.sons[i].kind = nkElifBranch then begin - while n.sons[i].kind = nkElifBranch do dec(i); - if (n.sons[i].kind <> nkOfBranch) then - InternalError(n.sons[i].info, 'transformCase'); - ifs := newNodeI(nkIfStmt, n.sons[i+1].info); - elsen := newNodeI(nkElse, ifs.info); - for j := i+1 to len-1 do addSon(ifs, n.sons[j]); - setLength(n.sons, i+2); - addSon(elsen, ifs); - n.sons[i+1] := elsen; - end - else if (n.sons[len-1].kind <> nkElse) and - not (skipTypes(n.sons[0].Typ, abstractVarRange).Kind in - [tyInt..tyInt64, tyChar, tyEnum]) then begin - //MessageOut(renderTree(n)); - elsen := newNodeI(nkElse, n.info); - addSon(elsen, newNodeI(nkNilLit, n.info)); - addSon(n, elsen) - end; - result := n; - for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]); -end; - -function transformArrayAccess(c: PTransf; n: PNode): PNode; -var - i: int; -begin - result := copyTree(n); - result.sons[0] := skipConv(result.sons[0]); - result.sons[1] := skipConv(result.sons[1]); - for i := 0 to sonsLen(result)-1 do - result.sons[i] := transform(c, result.sons[i]); -end; - -function getMergeOp(n: PNode): PSym; -begin - result := nil; - case n.kind of - nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: begin - if (n.sons[0].Kind = nkSym) and (n.sons[0].sym.kind = skProc) - and (sfMerge in n.sons[0].sym.flags) then - result := n.sons[0].sym; - end - else begin end - end -end; - -procedure flattenTreeAux(d, a: PNode; op: PSym); -var - i: int; - op2: PSym; -begin - op2 := getMergeOp(a); - if (op2 <> nil) and ((op2.id = op.id) - or (op.magic <> mNone) and (op2.magic = op.magic)) then - for i := 1 to sonsLen(a)-1 do - flattenTreeAux(d, a.sons[i], op) - else - // a is a "leaf", so add it: - addSon(d, copyTree(a)) -end; - -function flattenTree(root: PNode): PNode; -var - op: PSym; -begin - op := getMergeOp(root); - if op <> nil then begin - result := copyNode(root); - addSon(result, copyTree(root.sons[0])); - flattenTreeAux(result, root, op) - end - else - result := root -end; - -function transformCall(c: PTransf; n: PNode): PNode; -var - i, j: int; - m, a: PNode; - op: PSym; -begin - result := flattenTree(n); - for i := 0 to sonsLen(result)-1 do - result.sons[i] := transform(c, result.sons[i]); - op := getMergeOp(result); - if (op <> nil) and (op.magic <> mNone) and (sonsLen(result) >= 3) then begin - m := result; - result := newNodeIT(nkCall, m.info, m.typ); - addSon(result, copyTree(m.sons[0])); - j := 1; - while j < sonsLen(m) do begin - a := m.sons[j]; - inc(j); - if isConstExpr(a) then - while (j < sonsLen(m)) and isConstExpr(m.sons[j]) do begin - a := evalOp(op.magic, m, a, m.sons[j], nil); - inc(j) - end; - addSon(result, a); - end; - if sonsLen(result) = 2 then - result := result.sons[1]; - end - else if (result.sons[0].kind = nkSym) - and (result.sons[0].sym.kind = skMethod) then begin - // use the dispatcher for the call: - result := methodCall(result); - end - (* - else if result.sons[0].kind = nkSym then begin - // optimization still too aggressive - op := result.sons[0].sym; - if (op.magic = mNone) and (op.kind = skProc) - and ([sfSideEffect, sfForward, sfNoReturn, sfImportc] * op.flags = []) - then begin - for i := 1 to sonsLen(result)-1 do - if not isConstExpr(result.sons[i]) then exit; - // compile-time evaluation: - a := evalConstExpr(c.module, result); - if (a <> nil) and (a.kind <> nkEmpty) then begin - messageout('evaluated at compile time: ' + rendertree(result)); - result := a - end - end - end *) -end; - -function transform(c: PTransf; n: PNode): PNode; -var - i: int; - cnst: PNode; -begin - result := n; - if n = nil then exit; - //if ToLinenumber(n.info) = 32 then - // MessageOut(RenderTree(n)); - case n.kind of - nkSym: begin - result := transformSym(c, n); - exit - end; - nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: begin - // nothing to be done for leaves - end; - nkBracketExpr: result := transformArrayAccess(c, n); - nkLambda: result := transformLambda(c, n); - nkForStmt: result := transformFor(c, n); - nkCaseStmt: result := transformCase(c, n); - nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: begin - if n.sons[genericParamsPos] = nil then begin - n.sons[codePos] := transform(c, n.sons[codePos]); - if n.kind = nkMethodDef then - methodDef(n.sons[namePos].sym); - end - end; - nkWhileStmt: begin - if (sonsLen(n) <> 2) then InternalError(n.info, 'transform'); - n.sons[0] := transform(c, n.sons[0]); - n.sons[1] := transformContinue(c, n.sons[1]); - end; - nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: - result := transformCall(c, result); - nkAddr, nkHiddenAddr: - result := transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref); - nkDerefExpr, nkHiddenDeref: - result := transformAddrDeref(c, n, nkAddr, nkHiddenAddr); - nkHiddenStdConv, nkHiddenSubConv, nkConv: - result := transformConv(c, n); - nkDiscardStmt: begin - for i := 0 to sonsLen(n)-1 do - result.sons[i] := transform(c, n.sons[i]); - if isConstExpr(result.sons[0]) then - result := newNode(nkCommentStmt) - end; - nkCommentStmt, nkTemplateDef: exit; - nkConstSection: exit; // do not replace ``const c = 3`` with ``const 3 = 3`` - else begin - for i := 0 to sonsLen(n)-1 do - result.sons[i] := transform(c, n.sons[i]); - end - end; - cnst := getConstExpr(c.module, result); - if cnst <> nil then result := cnst; // do not miss an optimization -end; - -function processTransf(context: PPassContext; n: PNode): PNode; -var - c: PTransf; -begin - c := PTransf(context); - result := transform(c, n); -end; - -function openTransf(module: PSym; const filename: string): PPassContext; -var - n: PTransf; -begin - new(n); -{@ignore} - fillChar(n^, sizeof(n^), 0); -{@emit} - n.module := module; - result := n; -end; - -function transfPass(): TPass; -begin - initPass(result); - result.open := openTransf; - result.process := processTransf; - result.close := processTransf; // we need to process generics too! -end; - -end. |