diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim new file mode 100644 index 0000000000..f29a4e106e --- /dev/null +++ b/compiler/liftlocals.nim @@ -0,0 +1,68 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the '.liftLocals' pragma. + +import + intsets, strutils, options, ast, astalgo, msgs, + idents, renderer, types, lowerings + +from pragmas import getPragmaVal +from wordrecg import wLiftLocals + +type + Ctx = object + partialParam: PSym + objType: PType + +proc interestingVar(s: PSym): bool {.inline.} = + result = s.kind in {skVar, skLet, skTemp, skForVar, skResult} and + sfGlobal notin s.flags + +proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode = + let field = addUniqueField(c.objType, s) + var deref = newNodeI(nkHiddenDeref, info) + deref.typ = c.objType + add(deref, newSymNode(c.partialParam, info)) + result = newNodeI(nkDotExpr, info) + add(result, deref) + add(result, newSymNode(field)) + result.typ = field.typ + +proc liftLocals(n: PNode; i: int; c: var Ctx) = + let it = n[i] + case it.kind + of nkSym: + if interestingVar(it.sym): + n[i] = lookupOrAdd(c, it.sym, it.info) + of procDefs, nkTypeSection: discard + else: + for i in 0 ..< it.safeLen: + liftLocals(it, i, c) + +proc lookupParam(params, dest: PNode): PSym = + if dest.kind != nkIdent: return nil + for i in 1 ..< params.len: + if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id: + return params[i].sym + +proc liftLocalsIfRequested*(prc: PSym) = + let liftDest = getPragmaVal(prc.ast, wLiftLocals) + if liftDest == nil: return + let partialParam = lookupParam(prc.typ.n, liftDest) + if partialParam.isNil: + localError(liftDest.info, "'$1' is not a parameter of '$2'" % + [$liftDest, prc.name.s]) + return + let objType = partialParam.typ.skipTypes(abstractPtrs) + if objType.kind != tyObject or tfPartial notin objType.flags: + localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) + return + var c = Ctx(partialParam: partialParam, objType: objType) + liftLocals(prc.ast, bodyPos, c)