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

@ -664,6 +664,9 @@ proc `&` * (x, y: string): string {.
proc `&` * (x: char, y: string): string {. 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,9 +955,9 @@ 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
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) = proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =

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

@ -10,7 +10,7 @@
# module for calling the different external C compilers # module for calling the different external C compilers
# some things are read in from the configuration file # some things are read in from the configuration file
import import
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
type type

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 = n.info
labl.info = result.info c.blockSyms.add(labl)
transformContinueAux(c, result, labl, counter)
if counter > 0: result = newTransNode(nkBlockStmt, n.info, 2)
var x = newNodeI(nkBlockStmt, result.info) result[0] = newSymNode(labl).PTransNode
addSon(x, newSymNode(labl)) result[1] = transform(c, n)
addSon(x, result) discard c.blockSyms.pop()
result = x 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)
{tyInt..tyInt64, tyChar, tyEnum}): if ifs.pnode != nil:
#MessageOut(renderTree(n)); var elseBranch = newTransNode(nkElse, n.info, 1)
var elsen = newNodeI(nkElse, n.info) elseBranch[0] = ifs
addSon(elsen, newNodeI(nkNilLit, n.info)) result.add(elseBranch)
addSon(n, elsen) elif result.Pnode.lastSon.kind != nkElse and not (
result = n skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
for j in countup(0, sonsLen(n) - 1): result.sons[j] = transform(c, n.sons[j]) {tyInt..tyInt64, tyChar, tyEnum}):
# fix a stupid code gen bug by normalizing:
var elseBranch = newTransNode(nkElse, n.info, 1)
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
add(result, elseBranch)
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:
result = transformSons(c, n)
else: else:
result = shallowCopy(n) result = transformSons(c, n)
for i in countup(0, sonsLen(n) - 1): var cnst = getConstExpr(c.module, PNode(result))
result.sons[i] = transform(c, n.sons[i])
var cnst = getConstExpr(c.module, 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) !?