123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- #
- #
- # 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 common simple lowerings.
- const
- genPrefix* = ":tmp" # prefix for generated names
- import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs,
- lineinfos
- proc newDeref*(n: PNode): PNode {.inline.} =
- result = newNodeIT(nkHiddenDeref, n.info, n.typ[0])
- result.add n
- proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
- if tup.kind == nkHiddenAddr:
- result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}))
- result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})[i])
- result[0].add tup[0]
- var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
- lit.intVal = i
- result[0].add lit
- else:
- result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
- abstractInst)[i])
- result.add copyTree(tup)
- var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
- lit.intVal = i
- result.add lit
- proc addVar*(father, v: PNode) =
- var vpart = newNodeI(nkIdentDefs, v.info, 3)
- vpart[0] = v
- vpart[1] = newNodeI(nkEmpty, v.info)
- vpart[2] = vpart[1]
- father.add vpart
- proc addVar*(father, v, value: PNode) =
- var vpart = newNodeI(nkIdentDefs, v.info, 3)
- vpart[0] = v
- vpart[1] = newNodeI(nkEmpty, v.info)
- vpart[2] = value
- father.add vpart
- proc newAsgnStmt*(le, ri: PNode): PNode =
- result = newNodeI(nkAsgn, le.info, 2)
- result[0] = le
- result[1] = ri
- proc newFastAsgnStmt*(le, ri: PNode): PNode =
- result = newNodeI(nkFastAsgn, le.info, 2)
- result[0] = le
- result[1] = ri
- proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode =
- result = newNodeI(nkFastAsgn, le.info, 2)
- result[0] = le
- result[1] = newNodeIT(nkCall, ri.info, ri.typ)
- result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove))
- result[1].add ri
- proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
- assert n.kind == nkVarTuple
- let value = n.lastSon
- result = newNodeI(nkStmtList, n.info)
- var temp = newSym(skTemp, getIdent(g.cache, genPrefix), owner, value.info, g.config.options)
- temp.typ = skipTypes(value.typ, abstractInst)
- incl(temp.flags, sfFromGeneric)
- var v = newNodeI(nkVarSection, value.info)
- let tempAsNode = newSymNode(temp)
- v.addVar(tempAsNode, value)
- result.add(v)
- for i in 0..<n.len-2:
- let val = newTupleAccess(g, tempAsNode, i)
- if n[i].kind == nkSym: v.addVar(n[i], val)
- else: result.add newAsgnStmt(n[i], val)
- proc evalOnce*(g: ModuleGraph; value: PNode; owner: PSym): PNode =
- ## Turns (value) into (let tmp = value; tmp) so that 'value' can be re-used
- ## freely, multiple times. This is frequently required and such a builtin would also be
- ## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
- result = newNodeIT(nkStmtListExpr, value.info, value.typ)
- var temp = newSym(skTemp, getIdent(g.cache, genPrefix), owner, value.info, g.config.options)
- temp.typ = skipTypes(value.typ, abstractInst)
- incl(temp.flags, sfFromGeneric)
- var v = newNodeI(nkLetSection, value.info)
- let tempAsNode = newSymNode(temp)
- v.addVar(tempAsNode)
- result.add(v)
- result.add newAsgnStmt(tempAsNode, value)
- result.add tempAsNode
- proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
- result = newNodeI(nkBracketExpr, tup.info)
- result.add copyTree(tup)
- var lit = newNodeI(nkIntLit, tup.info)
- lit.intVal = i
- result.add lit
- proc newTryFinally*(body, final: PNode): PNode =
- result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
- proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
- let value = n.lastSon
- result = newNodeI(nkStmtList, n.info)
- var temp = newSym(skTemp, getIdent(g.cache, "_"), owner, value.info, owner.options)
- var v = newNodeI(nkLetSection, value.info)
- let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
- var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
- vpart[0] = tempAsNode
- vpart[1] = newNodeI(nkEmpty, value.info)
- vpart[2] = value
- v.add vpart
- result.add(v)
- let lhs = n[0]
- for i in 0..<lhs.len:
- result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
- proc lowerSwap*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
- result = newNodeI(nkStmtList, n.info)
- # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
- var temp = newSym(skVar, getIdent(g.cache, genPrefix), owner, n.info, owner.options)
- temp.typ = n[1].typ
- incl(temp.flags, sfFromGeneric)
- var v = newNodeI(nkVarSection, n.info)
- let tempAsNode = newSymNode(temp)
- var vpart = newNodeI(nkIdentDefs, v.info, 3)
- vpart[0] = tempAsNode
- vpart[1] = newNodeI(nkEmpty, v.info)
- vpart[2] = n[1]
- v.add vpart
- result.add(v)
- result.add newFastAsgnStmt(n[1], n[2])
- result.add newFastAsgnStmt(n[2], tempAsNode)
- proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType =
- result = newType(tyObject, owner)
- if final:
- rawAddSon(result, nil)
- incl result.flags, tfFinal
- else:
- rawAddSon(result, getCompilerProc(g, "RootObj").typ)
- result.n = newNodeI(nkRecList, info)
- let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info)),
- owner, info, owner.options)
- incl s.flags, sfAnon
- s.typ = result
- result.sym = s
- template fieldCheck {.dirty.} =
- when false:
- if tfCheckedForDestructor in obj.flags:
- echo "missed field ", field.name.s
- writeStackTrace()
- proc rawAddField*(obj: PType; field: PSym) =
- assert field.kind == skField
- field.position = obj.n.len
- obj.n.add newSymNode(field)
- propagateToOwner(obj, field.typ)
- fieldCheck()
- proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
- # returns a[].field as a node
- assert field.kind == skField
- var deref = newNodeI(nkHiddenDeref, info)
- deref.typ = a.typ.skipTypes(abstractInst)[0]
- deref.add a
- result = newNodeI(nkDotExpr, info)
- result.add deref
- result.add newSymNode(field)
- result.typ = field.typ
- proc rawDirectAccess*(obj, field: PSym): PNode =
- # returns a.field as a node
- assert field.kind == skField
- result = newNodeI(nkDotExpr, field.info)
- result.add newSymNode(obj)
- result.add newSymNode(field)
- result.typ = field.typ
- proc lookupInRecord(n: PNode, id: int): PSym =
- result = nil
- case n.kind
- of nkRecList:
- for i in 0..<n.len:
- result = lookupInRecord(n[i], id)
- if result != nil: return
- of nkRecCase:
- if n[0].kind != nkSym: return
- result = lookupInRecord(n[0], id)
- if result != nil: return
- for i in 1..<n.len:
- case n[i].kind
- of nkOfBranch, nkElse:
- result = lookupInRecord(lastSon(n[i]), id)
- if result != nil: return
- else: discard
- of nkSym:
- if n.sym.id == -abs(id): result = n.sym
- else: discard
- proc addField*(obj: PType; s: PSym; cache: IdentCache) =
- # because of 'gensym' support, we have to mangle the name with its ID.
- # This is hacky but the clean solution is much more complex than it looks.
- var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), s.owner, s.info,
- s.options)
- field.id = -s.id
- let t = skipIntLit(s.typ)
- field.typ = t
- assert t.kind != tyTyped
- propagateToOwner(obj, t)
- field.position = obj.n.len
- field.flags = s.flags * {sfCursor}
- obj.n.add newSymNode(field)
- fieldCheck()
- proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache): PSym {.discardable.} =
- result = lookupInRecord(obj.n, s.id)
- if result == nil:
- var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), s.owner, s.info,
- s.options)
- field.id = -s.id
- let t = skipIntLit(s.typ)
- field.typ = t
- assert t.kind != tyTyped
- propagateToOwner(obj, t)
- field.position = obj.n.len
- obj.n.add newSymNode(field)
- result = field
- proc newDotExpr*(obj, b: PSym): PNode =
- result = newNodeI(nkDotExpr, obj.info)
- let field = lookupInRecord(obj.typ.n, b.id)
- assert field != nil, b.name.s
- result.add newSymNode(obj)
- result.add newSymNode(field)
- result.typ = field.typ
- proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
- # returns a[].b as a node
- var deref = newNodeI(nkHiddenDeref, info)
- deref.typ = a.typ.skipTypes(abstractInst)[0]
- var t = deref.typ.skipTypes(abstractInst)
- var field: PSym
- while true:
- assert t.kind == tyObject
- field = lookupInRecord(t.n, b)
- if field != nil: break
- t = t[0]
- if t == nil: break
- t = t.skipTypes(skipPtrs)
- #if field == nil:
- # echo "FIELD ", b
- # debug deref.typ
- assert field != nil
- deref.add a
- result = newNodeI(nkDotExpr, info)
- result.add deref
- result.add newSymNode(field)
- result.typ = field.typ
- proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
- # returns a[].b as a node
- var deref = newNodeI(nkHiddenDeref, info)
- deref.typ = a.typ.skipTypes(abstractInst)[0]
- var t = deref.typ.skipTypes(abstractInst)
- var field: PSym
- let bb = getIdent(cache, b)
- while true:
- assert t.kind == tyObject
- field = getSymFromList(t.n, bb)
- if field != nil: break
- t = t[0]
- if t == nil: break
- t = t.skipTypes(skipPtrs)
- #if field == nil:
- # echo "FIELD ", b
- # debug deref.typ
- assert field != nil
- deref.add a
- result = newNodeI(nkDotExpr, info)
- result.add deref
- result.add newSymNode(field)
- result.typ = field.typ
- proc getFieldFromObj*(t: PType; v: PSym): PSym =
- assert v.kind != skField
- var t = t
- while true:
- assert t.kind == tyObject
- result = lookupInRecord(t.n, v.id)
- if result != nil: break
- t = t[0]
- if t == nil: break
- t = t.skipTypes(skipPtrs)
- proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
- # returns a[].b as a node
- result = indirectAccess(a, b.id, info)
- proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
- result = indirectAccess(newSymNode(a), b, info)
- proc genAddrOf*(n: PNode, typeKind = tyPtr): PNode =
- result = newNodeI(nkAddr, n.info, 1)
- result[0] = n
- result.typ = newType(typeKind, n.typ.owner)
- result.typ.rawAddSon(n.typ)
- proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
- result = newNodeIT(k, n.info,
- n.typ.skipTypes(abstractInst)[0])
- result.add n
- proc callCodegenProc*(g: ModuleGraph; name: string;
- info: TLineInfo = unknownLineInfo;
- arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
- result = newNodeI(nkCall, info)
- let sym = magicsys.getCompilerProc(g, name)
- if sym == nil:
- localError(g.config, info, "system module needs: " & name)
- else:
- result.add newSymNode(sym)
- if arg1 != nil: result.add arg1
- if arg2 != nil: result.add arg2
- if arg3 != nil: result.add arg3
- if optionalArgs != nil:
- for i in 1..<optionalArgs.len-2:
- result.add optionalArgs[i]
- result.typ = sym.typ[0]
- proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
- result = nkIntLit.newIntNode(value)
- result.typ = getSysType(g, info, tyInt)
- proc genHigh*(g: ModuleGraph; n: PNode): PNode =
- if skipTypes(n.typ, abstractVar).kind == tyArray:
- result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
- else:
- result = newNodeI(nkCall, n.info, 2)
- result.typ = getSysType(g, n.info, tyInt)
- result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
- result[1] = n
- proc genLen*(g: ModuleGraph; n: PNode): PNode =
- if skipTypes(n.typ, abstractVar).kind == tyArray:
- result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
- else:
- result = newNodeI(nkCall, n.info, 2)
- result.typ = getSysType(g, n.info, tyInt)
- result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
- result[1] = n
- proc hoistExpr*(varSection, expr: PNode, name: PIdent, owner: PSym): PSym =
- result = newSym(skLet, name, owner, varSection.info, owner.options)
- result.flags.incl sfHoisted
- result.typ = expr.typ
- var varDef = newNodeI(nkIdentDefs, varSection.info, 3)
- varDef[0] = newSymNode(result)
- varDef[1] = newNodeI(nkEmpty, varSection.info)
- varDef[2] = expr
- varSection.add varDef
|