transf: big refactoring; other small fixes

This commit is contained in:
Araq 2011-01-05 23:46:50 +01:00
commit 5635fde060
11 changed files with 286 additions and 225 deletions

View file

@ -17,7 +17,7 @@ Introduction
This document describes the usage of the *Nimrod compiler* This document describes the usage of the *Nimrod compiler*
on the different supported platforms. It is not a definition of the Nimrod on the different supported platforms. It is not a definition of the Nimrod
programming language (therefore is the `manual <manual>`_). programming language (therefore is the `manual <manual.html>`_).
Nimrod is free software; it is licensed under the Nimrod is free software; it is licensed under the
`GNU General Public License <gpl.html>`_. `GNU General Public License <gpl.html>`_.

View file

@ -159,6 +159,7 @@ when not defined(ECMAScript):
## same as ``sqrt(x*x + y*y)``. ## same as ``sqrt(x*x + y*y)``.
proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".} proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
proc sin*(x: float): float {.importc: "sin", header: "<math.h>".}
proc tan*(x: float): float {.importc: "tan", header: "<math.h>".} proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".} proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".} proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
@ -209,6 +210,7 @@ else:
proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5 proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5
proc hypot*(x, y: float): float = return sqrt(x*x + y*y) proc hypot*(x, y: float): float = return sqrt(x*x + y*y)
proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5 proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5
proc sin*(x: float): float {.importc: "Math.sin", nodecl.}
proc tan*(x: float): float {.importc: "Math.tan", nodecl.} proc tan*(x: float): float {.importc: "Math.tan", nodecl.}
proc tanh*(x: float): float = proc tanh*(x: float): float =
var y = exp(2.0*x) var y = exp(2.0*x)

View file

@ -665,6 +665,9 @@ proc `&` * (x: char, y: string): string {.
magic: "ConStrStr", noSideEffect, merge.} magic: "ConStrStr", noSideEffect, merge.}
## is the `concatenation operator`. It concatenates `x` and `y`. ## is the `concatenation operator`. It concatenates `x` and `y`.
# implementation note: These must all have the same magic value "ConStrStr" so
# that the merge optimization works properly.
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}

View file

@ -955,8 +955,8 @@ proc hasSubnodeWith(n: PNode, kind: TNodeKind): bool =
of nkEmpty..nkNilLit: result = n.kind == kind of nkEmpty..nkNilLit: result = n.kind == kind
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if (n.sons[i] != nil) and (n.sons[i].kind == kind) or if n.sons[i] != nil:
hasSubnodeWith(n.sons[i], kind): if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
return true return true
result = false result = false

View file

@ -259,7 +259,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
L.bufpos = pos L.bufpos = pos
proc getNumber8(L: var TLexer, tok: var TToken) = proc getNumber8(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0b var pos = L.bufpos + 1 # skip 0
tok.base = base8 tok.base = base8
var xi: biggestInt = 0 var xi: biggestInt = 0
var bits = 0 var bits = 0

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -201,4 +201,4 @@ proc generateMethodDispatchers(): PNode =
sortBucket(gMethods[bucket], relevantCols) sortBucket(gMethods[bucket], relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))
gMethods = @ [] gMethods = @[]

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2010 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -389,12 +389,12 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [ ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
"cstrToNimStr", "cstrToNimStr", "cstrToNimStr(($1)+\"\")", "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
"cstrToNimStr(($1)+\"\")"], ["cstrToNimStr", "cstrToNimStr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
"cstrToNimStr(($1)+\"\")", "cstrToNimstr(($1)+\"\")",
"cstrToNimStr(($1)+\"\")"], ["cstrToNimStr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
"cstrToNimStr", "cstrToNimStr(($1)+\"\")", "cstrToNimStr(($1)+\"\")"], "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
["cstrToNimStr", "cstrToNimStr", "cstrToNimStr($1)", "cstrToNimStr($1)"], ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
["", "", "$1", "$1"]] ["", "", "$1", "$1"]]
proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) =

View file

@ -13,7 +13,7 @@
# * inlines iterators # * inlines iterators
# * inlines constants # * inlines constants
# * performes contant folding # * performes contant folding
# * introduces nkHiddenDeref, nkHiddenSubConv, etc. # * converts "continue" to "break"
# * introduces method dispatchers # * introduces method dispatchers
import import
@ -27,20 +27,54 @@ proc transfPass*(): TPass
# implementation # implementation
type type
PTransNode* = distinct PNode
PTransCon = ref TTransCon PTransCon = ref TTransCon
TTransCon{.final.} = object # part of TContext; stackable TTransCon{.final.} = object # part of TContext; stackable
mapping: TIdNodeTable # mapping from symbols to nodes mapping: TIdNodeTable # mapping from symbols to nodes
owner: PSym # current owner owner: PSym # current owner
forStmt: PNode # current for stmt forStmt: PNode # current for stmt
forLoopBody: PTransNode # transformed for loop body
yieldStmts: int # we count the number of yield statements,
# because we need to introduce new variables
# if we encounter the 2nd yield statement
next: PTransCon # for stacking next: PTransCon # for stacking
TTransfContext = object of passes.TPassContext TTransfContext = object of passes.TPassContext
module: PSym module: PSym
transCon: PTransCon # top of a TransCon stack transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars) inlining: int # > 0 if we are in inlining context (copy vars)
blocksyms: seq[PSym]
PTransf = ref TTransfContext PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
result = PTransNode(shallowCopy(a))
proc newTransNode(kind: TNodeKind, info: TLineInfo,
sons: int): PTransNode {.inline.} =
var x = newNodeI(kind, info)
newSeq(x.sons, sons)
result = x.PTransNode
proc newTransNode(kind: TNodeKind, n: PNode,
sons: int): PTransNode {.inline.} =
var x = newNodeIT(kind, n.info, n.typ)
newSeq(x.sons, sons)
x.typ = n.typ
result = x.PTransNode
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
var n = PNode(a)
n.sons[i] = PNode(x)
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
var n = PNode(a)
result = n.sons[i].PTransNode
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
proc newTransCon(owner: PSym): PTransCon = proc newTransCon(owner: PSym): PTransCon =
assert owner != nil assert owner != nil
new(result) new(result)
@ -65,7 +99,12 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
result.typ = skipTypes(typ, {tyGenericInst}) result.typ = skipTypes(typ, {tyGenericInst})
incl(result.flags, sfFromGeneric) incl(result.flags, sfFromGeneric)
proc transform(c: PTransf, n: PNode): PNode proc transform(c: PTransf, n: PNode): PTransNode
proc transformSons(c: PTransf, n: PNode): PTransNode =
result = newTransNode(n)
for i in countup(0, sonsLen(n)-1):
result[i] = transform(c, n.sons[i])
# Transforming iterators into non-inlined versions is pretty hard, but # Transforming iterators into non-inlined versions is pretty hard, but
# unavoidable for not bloating the code too much. If we had direct access to # unavoidable for not bloating the code too much. If we had direct access to
@ -115,12 +154,12 @@ proc transform(c: PTransf, n: PNode): PNode
# label1: inc(c.i) # label1: inc(c.i)
# #
proc newAsgnStmt(c: PTransf, le, ri: PNode): PNode = proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
result = newNodeI(nkFastAsgn, ri.info) result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
addSon(result, le) result[0] = PTransNode(le)
addSon(result, ri) result[1] = ri
proc transformSym(c: PTransf, n: PNode): PNode = proc transformSymAux(c: PTransf, n: PNode): PNode =
var b: PNode var b: PNode
if (n.kind != nkSym): internalError(n.info, "transformSym") if (n.kind != nkSym): internalError(n.info, "transformSym")
var tc = c.transCon var tc = c.transCon
@ -131,12 +170,10 @@ proc transformSym(c: PTransf, n: PNode): PNode =
b = newSymNode(b.sym) b = newSymNode(b.sym)
b.info = n.info b.info = n.info
else: else:
b = n #writeln('transformSym', n.sym.id : 5); b = n
while tc != nil: while tc != nil:
result = IdNodeTableGet(tc.mapping, b.sym) result = IdNodeTableGet(tc.mapping, b.sym)
if result != nil: if result != nil: return
return #write('not found in: ');
#writeIdNodeTable(tc.mapping);
tc = tc.next tc = tc.next
result = b result = b
case b.sym.kind case b.sym.kind
@ -148,33 +185,33 @@ proc transformSym(c: PTransf, n: PNode): PNode =
else: else:
nil nil
proc transformContinueAux(c: PTransf, n: PNode, labl: PSym, counter: var int) = proc transformSym(c: PTransf, n: PNode): PTransNode =
result = PTransNode(transformSymAux(c, n))
proc hasContinue(n: PNode): bool =
if n == nil: return if n == nil: return
case n.kind case n.kind
of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: nil
nil of nkContinueStmt: result = true
of nkContinueStmt:
n.kind = nkBreakStmt
addSon(n, newSymNode(labl))
inc(counter)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
transformContinueAux(c, n.sons[i], labl, counter) if hasContinue(n.sons[i]): return true
proc transformContinue(c: PTransf, n: PNode): PNode = proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
# we transform the continue statement into a block statement # XXX BUG: What if it contains "continue" and "break"? "break" needs
result = n # an explicit label too, but not the same!
for i in countup(0, sonsLen(n) - 1): result.sons[i] = transform(c, n.sons[i]) if hasContinue(n):
var counter = 0
var labl = newSym(skLabel, nil, getCurrOwner(c)) var labl = newSym(skLabel, nil, getCurrOwner(c))
labl.name = getIdent(genPrefix & $(labl.id)) labl.name = getIdent(genPrefix & $labl.id)
labl.info = result.info labl.info = n.info
transformContinueAux(c, result, labl, counter) c.blockSyms.add(labl)
if counter > 0:
var x = newNodeI(nkBlockStmt, result.info) result = newTransNode(nkBlockStmt, n.info, 2)
addSon(x, newSymNode(labl)) result[0] = newSymNode(labl).PTransNode
addSon(x, result) result[1] = transform(c, n)
result = x discard c.blockSyms.pop()
else:
result = transform(c, n)
proc skipConv(n: PNode): PNode = proc skipConv(n: PNode): PNode =
case n.kind case n.kind
@ -192,83 +229,69 @@ proc newTupleAccess(tup: PNode, i: int): PNode =
lit.intVal = i lit.intVal = i
addSon(result, lit) addSon(result, lit)
proc unpackTuple(c: PTransf, n, father: PNode) = proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
# XXX: BUG: what if `n` is an expression with side-effects? # XXX: BUG: what if `n` is an expression with side-effects?
for i in countup(0, sonsLen(c.transCon.forStmt) - 3): for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
addSon(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
transform(c, newTupleAccess(n, i)))) transform(c, newTupleAccess(n, i))))
proc transformYield(c: PTransf, n: PNode): PNode = proc transformYield(c: PTransf, n: PNode): PTransNode =
result = newNodeI(nkStmtList, n.info) result = newTransNode(nkStmtList, n.info, 0)
var e = n.sons[0] var e = n.sons[0]
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple: if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple:
e = skipConv(e) e = skipConv(e)
if e.kind == nkPar: if e.kind == nkPar:
for i in countup(0, sonsLen(e) - 1): for i in countup(0, sonsLen(e) - 1):
addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
transform(c, copyTree(e.sons[i])))) transform(c, e.sons[i])))
else: else:
unpackTuple(c, e, result) unpackTuple(c, e, result)
else: else:
e = transform(c, copyTree(e)) var x = transform(c, e)
addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], e)) add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
#var tc = newTransCon(c.transCon.owner) inc(c.transCon.yieldStmts)
#tc.forStmt = c.transCon.forStmt if c.transCon.yieldStmts <= 1:
#pushTransCon(c, tc) # common case
inc(c.inlining) add(result, c.transCon.forLoopBody)
addSon(result, transform(c, lastSon(c.transCon.forStmt))) else:
dec(c.inlining) # we need to transform again to introduce new local variables:
#popTransCon(c) add(result, transform(c, c.transCon.forLoopBody.pnode))
proc transformVarSection(c: PTransf, v: PNode): PNode = proc transformVarSection(c: PTransf, v: PNode): PTransNode =
result = copyTree(v) result = newTransNode(v)
for i in countup(0, sonsLen(result) - 1): for i in countup(0, sonsLen(v)-1):
var it = result.sons[i] var it = v.sons[i]
if it.kind == nkCommentStmt: continue if it.kind == nkCommentStmt:
if it.kind == nkIdentDefs: result[i] = PTransNode(it)
elif it.kind == nkIdentDefs:
if (it.sons[0].kind != nkSym): if (it.sons[0].kind != nkSym):
InternalError(it.info, "transformVarSection") InternalError(it.info, "transformVarSection")
var newVar = copySym(it.sons[0].sym) var newVar = copySym(it.sons[0].sym)
if identEq(newVar.name, "titer2TestVar"):
echo "created a copy of titer2TestVar ", newVar.id, " ",
it.sons[0].sym.id
incl(newVar.flags, sfFromGeneric) incl(newVar.flags, sfFromGeneric)
# fixes a strange bug for rodgen: # fixes a strange bug for rodgen:
#include(it.sons[0].sym.flags, sfFromGeneric); #include(it.sons[0].sym.flags, sfFromGeneric);
newVar.owner = getCurrOwner(c) newVar.owner = getCurrOwner(c)
IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar)) IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar))
it.sons[0].sym = newVar var defs = newTransNode(nkIdentDefs, it.info, 3)
it.sons[2] = transform(c, it.sons[2]) defs[0] = newSymNode(newVar).PTransNode
defs[1] = it.sons[1].PTransNode
defs[2] = transform(c, it.sons[2])
result[i] = defs
else: else:
if it.kind != nkVarTuple: if it.kind != nkVarTuple:
InternalError(it.info, "transformVarSection: not nkVarTuple") InternalError(it.info, "transformVarSection: not nkVarTuple")
var L = sonsLen(it) var L = sonsLen(it)
for j in countup(0, L - 3): var defs = newTransNode(it.kind, it.info, L)
for j in countup(0, L-3):
var newVar = copySym(it.sons[j].sym) var newVar = copySym(it.sons[j].sym)
incl(newVar.flags, sfFromGeneric) incl(newVar.flags, sfFromGeneric)
newVar.owner = getCurrOwner(c) newVar.owner = getCurrOwner(c)
IdNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar)) IdNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar))
it.sons[j] = newSymNode(newVar) defs[j] = newSymNode(newVar).PTransNode
assert(it.sons[L - 2] == nil) assert(it.sons[L-2] == nil)
it.sons[L - 1] = transform(c, it.sons[L - 1]) defs[L-1] = transform(c, it.sons[L-1])
result[i] = defs
proc inlineIter(c: PTransf, n: PNode): PNode =
# n: iterator body
result = n
if n == nil: return
case n.kind
of nkEmpty..nkNilLit:
result = transform(c, copyTree(n))
of nkYieldStmt:
result = transformYield(c, n)
of nkVarSection:
result = transformVarSection(c, n)
else:
result = copyNode(n)
for i in countup(0, sonsLen(n) - 1): addSon(result, inlineIter(c, n.sons[i]))
result = transform(c, result)
proc addVar(father, v: PNode) = proc addVar(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info) var vpart = newNodeI(nkIdentDefs, v.info)
@ -277,98 +300,124 @@ proc addVar(father, v: PNode) =
addSon(vpart, nil) addSon(vpart, nil)
addSon(father, vpart) addSon(father, vpart)
proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
case n.sons[0].kind case n.sons[0].kind
of nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, nkChckRangeF, of nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, nkChckRangeF,
nkChckRange64: nkChckRange64:
var m = n.sons[0].sons[0] var m = n.sons[0].sons[0]
if (m.kind == a) or (m.kind == b): if (m.kind == a) or (m.kind == b):
# addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x) # addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x)
n.sons[0].sons[0] = m.sons[0] var x = copyTree(n)
return transform(c, n.sons[0]) x.sons[0].sons[0] = m.sons[0]
result = transform(c, x.sons[0])
#result = newTransNode(n.sons[0])
#result[0] = transform(c, m.sons[0])
else:
result = transformSons(c, n)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var m = n.sons[0].sons[1] var m = n.sons[0].sons[1]
if (m.kind == a) or (m.kind == b): if (m.kind == a) or (m.kind == b):
# addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
n.sons[0].sons[1] = m.sons[0]
return transform(c, n.sons[0]) var x = copyTree(n)
x.sons[0].sons[1] = m.sons[0]
result = transform(c, x.sons[0])
#result = newTransNode(n.sons[0])
#result[1] = transform(c, m.sons[0])
#if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
# debug(result.pnode)
# liMessage(n.info, warnUser,
# "nkPassAsOpenArray introduced here " & renderTree(n))
else:
result = transformSons(c, n)
else: else:
if (n.sons[0].kind == a) or (n.sons[0].kind == b): if (n.sons[0].kind == a) or (n.sons[0].kind == b):
# addr ( deref ( x )) --> x # addr ( deref ( x )) --> x
return transform(c, n.sons[0].sons[0]) result = transform(c, n.sons[0].sons[0])
n.sons[0] = transform(c, n.sons[0]) else:
result = n result = transformSons(c, n)
proc transformConv(c: PTransf, n: PNode): PNode = proc transformConv(c: PTransf, n: PNode): PTransNode =
n.sons[1] = transform(c, n.sons[1]) # numeric types need range checks:
result = n # numeric types need range checks:
var dest = skipTypes(n.typ, abstractVarRange) var dest = skipTypes(n.typ, abstractVarRange)
var source = skipTypes(n.sons[1].typ, abstractVarRange) var source = skipTypes(n.sons[1].typ, abstractVarRange)
case dest.kind case dest.kind
of tyInt..tyInt64, tyEnum, tyChar, tyBool: of tyInt..tyInt64, tyEnum, tyChar, tyBool:
if not isOrdinalType(source): if not isOrdinalType(source):
# XXX int64 -> float conversion? # XXX int64 -> float conversion?
result = n result = transformSons(c, n)
elif firstOrd(dest) <= firstOrd(source) and elif firstOrd(dest) <= firstOrd(source) and
lastOrd(source) <= lastOrd(dest): lastOrd(source) <= lastOrd(dest):
# BUGFIX: simply leave n as it is; we need a nkConv node, # BUGFIX: simply leave n as it is; we need a nkConv node,
# but no range check: # but no range check:
result = n result = transformSons(c, n)
else: else:
# generate a range check: # generate a range check:
if (dest.kind == tyInt64) or (source.kind == tyInt64): if (dest.kind == tyInt64) or (source.kind == tyInt64):
result = newNodeIT(nkChckRange64, n.info, n.typ) result = newTransNode(nkChckRange64, n, 3)
else: else:
result = newNodeIT(nkChckRange, n.info, n.typ) result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar) dest = skipTypes(n.typ, abstractVar)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
addSon(result, newIntTypeNode(nkIntLit, firstOrd(dest), source)) result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
addSon(result, newIntTypeNode(nkIntLit, lastOrd(dest), source)) result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
if skipTypes(n.typ, abstractVar).kind == tyRange: if skipTypes(n.typ, abstractVar).kind == tyRange:
result = newNodeIT(nkChckRangeF, n.info, n.typ) result = newTransNode(nkChckRangeF, n, 3)
dest = skipTypes(n.typ, abstractVar) dest = skipTypes(n.typ, abstractVar)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
addSon(result, copyTree(dest.n.sons[0])) result[1] = copyTree(dest.n.sons[0]).PTransNode
addSon(result, copyTree(dest.n.sons[1])) result[2] = copyTree(dest.n.sons[1]).PTransNode
else:
result = transformSons(c, n)
of tyOpenArray: of tyOpenArray:
result = newNodeIT(nkPassAsOpenArray, n.info, n.typ) result = newTransNode(nkPassAsOpenArray, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
of tyCString: of tyCString:
if source.kind == tyString: if source.kind == tyString:
result = newNodeIT(nkStringToCString, n.info, n.typ) result = newTransNode(nkStringToCString, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
else:
result = transformSons(c, n)
of tyString: of tyString:
if source.kind == tyCString: if source.kind == tyCString:
result = newNodeIT(nkCStringToString, n.info, n.typ) result = newTransNode(nkCStringToString, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
else:
result = transformSons(c, n)
of tyRef, tyPtr: of tyRef, tyPtr:
dest = skipTypes(dest, abstractPtrs) dest = skipTypes(dest, abstractPtrs)
source = skipTypes(source, abstractPtrs) source = skipTypes(source, abstractPtrs)
if source.kind == tyObject: if source.kind == tyObject:
var diff = inheritanceDiff(dest, source) var diff = inheritanceDiff(dest, source)
if diff < 0: if diff < 0:
result = newNodeIT(nkObjUpConv, n.info, n.typ) result = newTransNode(nkObjUpConv, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
elif diff > 0: elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, n.typ) result = newTransNode(nkObjDownConv, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
else: else:
result = n.sons[1] result = transform(c, n.sons[1])
else:
result = transformSons(c, n)
of tyObject: of tyObject:
var diff = inheritanceDiff(dest, source) var diff = inheritanceDiff(dest, source)
if diff < 0: if diff < 0:
result = newNodeIT(nkObjUpConv, n.info, n.typ) result = newTransNode(nkObjUpConv, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
elif diff > 0: elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, n.typ) result = newTransNode(nkObjDownConv, n, 1)
addSon(result, n.sons[1]) result[0] = transform(c, n.sons[1])
else: else:
result = n.sons[1] result = transform(c, n.sons[1])
of tyGenericParam, tyOrdinal: of tyGenericParam, tyOrdinal:
result = n.sons[1] # happens sometimes for generated assignments, etc. result = transform(c, n.sons[1])
# happens sometimes for generated assignments, etc.
else: else:
nil result = transformSons(c, n)
proc skipPassAsOpenArray(n: PNode): PNode = proc skipPassAsOpenArray(n: PNode): PNode =
result = n result = n
@ -396,32 +445,31 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
else: result = paFastAsgn else: result = paFastAsgn
proc transformFor(c: PTransf, n: PNode): PNode = proc transformFor(c: PTransf, n: PNode): PTransNode =
# generate access statements for the parameters (unless they are constant) # generate access statements for the parameters (unless they are constant)
# put mapping from formal parameters to actual parameters # put mapping from formal parameters to actual parameters
if (n.kind != nkForStmt): InternalError(n.info, "transformFor") if n.kind != nkForStmt: InternalError(n.info, "transformFor")
result = newNodeI(nkStmtList, n.info) result = newTransNode(nkStmtList, n.info, 0)
var length = sonsLen(n) var length = sonsLen(n)
n.sons[length - 1] = transformContinue(c, n.sons[length - 1]) var loopBody = transformLoopBody(c, n.sons[length-1])
var v = newNodeI(nkVarSection, n.info) var v = newNodeI(nkVarSection, n.info)
for i in countup(0, length - 3): for i in countup(0, length - 3):
addVar(v, copyTree(n.sons[i])) # declare new vars addVar(v, copyTree(n.sons[i])) # declare new vars
addSon(result, v) add(result, v.ptransNode)
var call = n.sons[length - 2] var call = n.sons[length - 2]
if (call.kind != nkCall) or (call.sons[0].kind != nkSym): if (call.kind != nkCall) or (call.sons[0].kind != nkSym):
InternalError(call.info, "transformFor") InternalError(call.info, "transformFor")
var newC = newTransCon(call.sons[0].sym) var newC = newTransCon(call.sons[0].sym)
newC.forStmt = n newC.forStmt = n
newC.forLoopBody = loopBody
if (newC.owner.kind != skIterator): if (newC.owner.kind != skIterator):
InternalError(call.info, "transformFor") InternalError(call.info, "transformFor")
# generate access statements for the parameters (unless they are constant) # generate access statements for the parameters (unless they are constant)
pushTransCon(c, newC) pushTransCon(c, newC)
for i in countup(1, sonsLen(call) - 1): for i in countup(1, sonsLen(call) - 1):
var arg = skipPassAsOpenArray(transform(c, call.sons[i])) var arg = skipPassAsOpenArray(transform(c, call.sons[i]).pnode)
var formal = skipTypes(newC.owner.typ, abstractInst).n.sons[i].sym var 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) case putArgInto(arg, formal.typ)
of paDirectMapping: of paDirectMapping:
IdNodeTablePut(newC.mapping, formal, arg) IdNodeTablePut(newC.mapping, formal, arg)
@ -429,14 +477,16 @@ proc transformFor(c: PTransf, n: PNode): PNode =
# generate a temporary and produce an assignment statement: # generate a temporary and produce an assignment statement:
var temp = newTemp(c, formal.typ, formal.info) var temp = newTemp(c, formal.typ, formal.info)
addVar(v, newSymNode(temp)) addVar(v, newSymNode(temp))
addSon(result, newAsgnStmt(c, newSymNode(temp), arg)) add(result, newAsgnStmt(c, newSymNode(temp), arg.ptransNode))
IdNodeTablePut(newC.mapping, formal, newSymNode(temp)) IdNodeTablePut(newC.mapping, formal, newSymNode(temp))
of paVarAsgn: of paVarAsgn:
assert(skipTypes(formal.typ, abstractInst).kind == tyVar) assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
InternalError(arg.info, "not implemented: pass to var parameter") InternalError(arg.info, "not implemented: pass to var parameter")
var body = newC.owner.ast.sons[codePos] var body = newC.owner.ast.sons[codePos]
pushInfoContext(n.info) pushInfoContext(n.info)
addSon(result, inlineIter(c, body)) inc(c.inlining)
add(result, transform(c, body))
dec(c.inlining)
popInfoContext() popInfoContext()
popTransCon(c) popTransCon(c)
@ -510,58 +560,58 @@ proc transformLambda(c: PTransf, n: PNode): PNode =
IdNodeTablePut(newC.mapping, closure.sons[i].sym, IdNodeTablePut(newC.mapping, closure.sons[i].sym,
indirectAccess(param, closure.sons[i].sym)) indirectAccess(param, closure.sons[i].sym))
pushTransCon(c, newC) pushTransCon(c, newC)
n.sons[codePos] = transform(c, n.sons[codePos]) n.sons[codePos] = transform(c, n.sons[codePos]).pnode
popTransCon(c) popTransCon(c)
proc transformCase(c: PTransf, n: PNode): PNode = proc transformCase(c: PTransf, n: PNode): PTransNode =
# removes `elif` branches of a case stmt # removes `elif` branches of a case stmt
# adds ``else: nil`` if needed for the code generator # adds ``else: nil`` if needed for the code generator
var length = sonsLen(n) result = newTransNode(nkCaseStmt, n, 0)
var i = length - 1 var ifs = PTransNode(nil)
if n.sons[i].kind == nkElse: dec(i) for i in 0 .. sonsLen(n)-1:
if n.sons[i].kind == nkElifBranch: var it = n.sons[i]
while n.sons[i].kind == nkElifBranch: dec(i) var e = transform(c, it)
if (n.sons[i].kind != nkOfBranch): case it.kind
InternalError(n.sons[i].info, "transformCase") of nkElifBranch:
var ifs = newNodeI(nkIfStmt, n.sons[i + 1].info) if ifs.pnode == nil:
var elsen = newNodeI(nkElse, ifs.info) ifs = newTransNode(nkIfStmt, it.info, 0)
for j in countup(i + 1, length - 1): addSon(ifs, n.sons[j]) ifs.add(e)
setlen(n.sons, i + 2) of nkElse:
addSon(elsen, ifs) if ifs.pnode == nil: result.add(e)
n.sons[i + 1] = elsen else: ifs.add(e)
elif (n.sons[length - 1].kind != nkElse) and else:
not (skipTypes(n.sons[0].Typ, abstractVarRange).Kind in result.add(e)
if ifs.pnode != nil:
var elseBranch = newTransNode(nkElse, n.info, 1)
elseBranch[0] = ifs
result.add(elseBranch)
elif result.Pnode.lastSon.kind != nkElse and not (
skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
{tyInt..tyInt64, tyChar, tyEnum}): {tyInt..tyInt64, tyChar, tyEnum}):
#MessageOut(renderTree(n)); # fix a stupid code gen bug by normalizing:
var elsen = newNodeI(nkElse, n.info) var elseBranch = newTransNode(nkElse, n.info, 1)
addSon(elsen, newNodeI(nkNilLit, n.info)) elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
addSon(n, elsen) add(result, elseBranch)
result = n
for j in countup(0, sonsLen(n) - 1): result.sons[j] = transform(c, n.sons[j])
proc transformArrayAccess(c: PTransf, n: PNode): PNode = proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
result = copyTree(n) result = newTransNode(n)
result.sons[0] = skipConv(result.sons[0]) result[0] = transform(c, skipConv(n.sons[0]))
result.sons[1] = skipConv(result.sons[1]) result[1] = transform(c, skipConv(n.sons[1]))
for i in countup(0, sonsLen(result) - 1):
result.sons[i] = transform(c, result.sons[i])
proc getMergeOp(n: PNode): PSym = proc getMergeOp(n: PNode): PSym =
result = nil
case n.kind case n.kind
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
nkCallStrLit: nkCallStrLit:
if (n.sons[0].Kind == nkSym) and (n.sons[0].sym.kind == skProc) and if (n.sons[0].Kind == nkSym) and (n.sons[0].sym.kind == skProc) and
(sfMerge in n.sons[0].sym.flags): (sfMerge in n.sons[0].sym.flags):
result = n.sons[0].sym result = n.sons[0].sym
else: else: nil
nil
proc flattenTreeAux(d, a: PNode, op: PSym) = proc flattenTreeAux(d, a: PNode, op: PSym) =
var op2 = getMergeOp(a) var op2 = getMergeOp(a)
if op2 != nil and if op2 != nil and
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic): (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
for i in countup(1, sonsLen(a) - 1): flattenTreeAux(d, a.sons[i], op) for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
else: else:
addSon(d, copyTree(a)) addSon(d, copyTree(a))
@ -574,57 +624,60 @@ proc flattenTree(root: PNode): PNode =
else: else:
result = root result = root
proc transformCall(c: PTransf, n: PNode): PNode = proc transformCall(c: PTransf, n: PNode): PTransNode =
result = flattenTree(n) var n = flattenTree(n)
for i in countup(0, sonsLen(result) - 1): var op = getMergeOp(n)
result.sons[i] = transform(c, result.sons[i]) if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
var op = getMergeOp(result) result = newTransNode(nkCall, n, 0)
if (op != nil) and (op.magic != mNone) and (sonsLen(result) >= 3): add(result, transform(c, n.sons[0]))
var m = result
result = newNodeIT(nkCall, m.info, m.typ)
addSon(result, copyTree(m.sons[0]))
var j = 1 var j = 1
while j < sonsLen(m): while j < sonsLen(n):
var a = m.sons[j] var a = n.sons[j]
inc(j) inc(j)
if isConstExpr(a): if isConstExpr(a):
while (j < sonsLen(m)) and isConstExpr(m.sons[j]): while (j < sonsLen(n)) and isConstExpr(n.sons[j]):
a = evalOp(op.magic, m, a, m.sons[j], nil) a = evalOp(op.magic, n, a, n.sons[j], nil)
inc(j) inc(j)
addSon(result, a) add(result, transform(c, a))
if sonsLen(result) == 2: result = result.sons[1] if len(result) == 2: result = result[1]
elif (result.sons[0].kind == nkSym) and elif (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skMethod):
(result.sons[0].sym.kind == skMethod):
# use the dispatcher for the call: # use the dispatcher for the call:
result = methodCall(result) result = methodCall(transformSons(c, n).pnode).ptransNode
else:
result = transformSons(c, n)
proc transform(c: PTransf, n: PNode): PNode = proc transform(c: PTransf, n: PNode): PTransNode =
result = n
if n == nil: return if n == nil: return
case n.kind case n.kind
of nkSym: of nkSym:
return transformSym(c, n) return transformSym(c, n)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
# nothing to be done for leaves # nothing to be done for leaves:
result = PTransNode(n)
of nkBracketExpr: of nkBracketExpr:
result = transformArrayAccess(c, n) result = transformArrayAccess(c, n)
of nkLambda: of nkLambda:
result = transformLambda(c, n) when false: result = transformLambda(c, n)
of nkForStmt: of nkForStmt:
result = transformFor(c, n) result = transformFor(c, n)
of nkCaseStmt: of nkCaseStmt:
result = transformCase(c, n) result = transformCase(c, n)
of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef:
if n.sons[genericParamsPos] == nil: if n.sons[genericParamsPos] == nil:
n.sons[codePos] = transform(c, n.sons[codePos]) n.sons[codePos] = PNode(transform(c, n.sons[codePos]))
if n.kind == nkMethodDef: methodDef(n.sons[namePos].sym) if n.kind == nkMethodDef: methodDef(n.sons[namePos].sym)
result = PTransNode(n)
of nkContinueStmt:
result = PTransNode(newNode(nkBreakStmt))
var labl = c.blockSyms[c.blockSyms.high]
add(result, PTransNode(newSymNode(labl)))
of nkWhileStmt: of nkWhileStmt:
if (sonsLen(n) != 2): InternalError(n.info, "transform") result = newTransNode(n)
n.sons[0] = transform(c, n.sons[0]) result[0] = transform(c, n.sons[0])
n.sons[1] = transformContinue(c, n.sons[1]) result[1] = transformLoopBody(c, n.sons[1])
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
nkCallStrLit: nkCallStrLit:
result = transformCall(c, result) result = transformCall(c, n)
of nkAddr, nkHiddenAddr: of nkAddr, nkHiddenAddr:
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref) result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
of nkDerefExpr, nkHiddenDeref: of nkDerefExpr, nkHiddenDeref:
@ -632,39 +685,42 @@ proc transform(c: PTransf, n: PNode): PNode =
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = transformConv(c, n) result = transformConv(c, n)
of nkDiscardStmt: of nkDiscardStmt:
for i in countup(0, sonsLen(n) - 1): result = transformSons(c, n)
result.sons[i] = transform(c, n.sons[i]) if isConstExpr(PNode(result).sons[0]):
if isConstExpr(result.sons[0]): result = newNode(nkCommentStmt) # ensure that e.g. discard "some comment" gets optimized away completely:
result = PTransNode(newNode(nkCommentStmt))
of nkCommentStmt, nkTemplateDef: of nkCommentStmt, nkTemplateDef:
return return n.ptransNode
of nkConstSection: of nkConstSection:
# do not replace ``const c = 3`` with ``const 3 = 3`` # do not replace ``const c = 3`` with ``const 3 = 3``
return return n.ptransNode
of nkVarSection: of nkVarSection:
if c.inlining > 0: if c.inlining > 0:
# we need to copy the variables for multiple yield statements: # we need to copy the variables for multiple yield statements:
result = transformVarSection(c, n) result = transformVarSection(c, n)
else: else:
result = shallowCopy(n) result = transformSons(c, n)
for i in countup(0, sonsLen(n) - 1): of nkYieldStmt:
result.sons[i] = transform(c, n.sons[i]) if c.inlining > 0:
result = transformYield(c, n)
else: else:
result = shallowCopy(n) result = transformSons(c, n)
for i in countup(0, sonsLen(n) - 1): else:
result.sons[i] = transform(c, n.sons[i]) result = transformSons(c, n)
var cnst = getConstExpr(c.module, result) var cnst = getConstExpr(c.module, PNode(result))
if cnst != nil: if cnst != nil:
result = cnst # do not miss an optimization result = PTransNode(cnst) # do not miss an optimization
proc processTransf(context: PPassContext, n: PNode): PNode = proc processTransf(context: PPassContext, n: PNode): PNode =
var c = PTransf(context) var c = PTransf(context)
pushTransCon(c, newTransCon(getCurrOwner(c))) pushTransCon(c, newTransCon(getCurrOwner(c)))
result = transform(c, n) result = PNode(transform(c, n))
popTransCon(c) popTransCon(c)
proc openTransf(module: PSym, filename: string): PPassContext = proc openTransf(module: PSym, filename: string): PPassContext =
var n: PTransf var n: PTransf
new(n) new(n)
n.blocksyms = @[]
n.module = module n.module = module
result = n result = n

View file

@ -28,7 +28,7 @@ tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloat
tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp] tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]
tformat.nim;Hi Andreas! How do you feel, Rumpf? tformat.nim;Hi Andreas! How do you feel, Rumpf?
thintoff.nim;0 thintoff.nim;0
tinit.nim;Hallo from module! Hallo from main module! tinit.nim;Hello from module! Hello from main module!
tints.nim;Success tints.nim;Success
tisopr.nim;falsetrue tisopr.nim;falsetrue
titer2.nim;123 titer2.nim;123

1 tack.nim 125
28 tfloat2.nim Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]
29 tformat.nim Hi Andreas! How do you feel, Rumpf?
30 thintoff.nim 0
31 tinit.nim Hallo from module! Hallo from main module! Hello from module! Hello from main module!
32 tints.nim Success
33 tisopr.nim falsetrue
34 titer2.nim 123

View file

@ -1,13 +1,13 @@
High priority (version 0.9.0) High priority (version 0.9.0)
============================= =============================
- transf should use distinct types; shallowCopy() for PNode
- fix implicit generic routines - fix implicit generic routines
- fix the streams implementation so that it uses methods - fix the streams implementation so that it uses methods
- fix overloading resolution - fix overloading resolution
- wrong co-/contravariance - wrong co-/contravariance
Bugs Bugs
---- ----
- proc (x: int) is passable to proc (x: var int) !? - proc (x: int) is passable to proc (x: var int) !?