Merge branch 'devel'

Conflicts:
	compiler/nversion.nim
This commit is contained in:
Araq 2014-12-29 13:50:18 +01:00
commit 647aadc1ea
624 changed files with 28569 additions and 20584 deletions

19
build.sh Normal file
View file

@ -0,0 +1,19 @@
#!/bin/sh
set -e
set -x
if [ ! -d "csources" ]; then
git clone --depth 1 https://github.com/nim-lang/csources.git
fi
cd "csources"
sh build.sh
cd ".."
./bin/nim c koch
./koch boot -d:release
cp -f install.sh.template install.sh
chmod +x install.sh
exit 0

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -16,9 +16,9 @@ type
TAnalysisResult* = enum
arNo, arMaybe, arYes
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo
case n.kind
of nkRecList:
@ -39,7 +39,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
result = isPartOfAux(n.sym.typ, b, marker)
else: internalError(n.info, "isPartOfAux()")
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo
if a == nil or b == nil: return
if containsOrIncl(marker, a.id): return

View file

@ -160,6 +160,7 @@ type
nkConstDef, # a const definition
nkTypeDef, # a type definition
nkYieldStmt, # the yield statement as a tree
nkDefer, # the 'defer' statement
nkTryStmt, # a try statement
nkFinally, # a finally section
nkRaiseStmt, # a raise statement
@ -293,6 +294,7 @@ const
# require RC ops
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
const
# getting ready for the future expr/stmt merge
@ -566,8 +568,8 @@ type
mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
mIsMainModule, mCompileDate, mCompileTime, mProcCall,
mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
@ -610,7 +612,7 @@ const
# thus cannot be overloaded (also documented in the spec!):
SpecialSemMagics* = {
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn}
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
type
PNode* = ref TNode
@ -681,7 +683,6 @@ type
heapRoot*: PRope # keeps track of the enclosing heap object that
# owns this location (required by GC algorithms
# employing heap snapshots or sliding views)
a*: int
# ---------------- end of backend information ------------------------------
@ -734,7 +735,7 @@ type
# check for the owner when touching 'usedGenerics'.
usedGenerics*: seq[PInstantiation]
tab*: TStrTable # interface table for modules
of skLet, skVar, skField:
of skLet, skVar, skField, skForVar:
guard*: PSym
else: nil
magic*: TMagic
@ -772,6 +773,7 @@ type
# it won't cause problems
TTypeSeq* = seq[PType]
TLockLevel* = distinct int16
TType* {.acyclic.} = object of TIdObj # \
# types are identical iff they have the
# same id; there may be multiple copies of a type
@ -798,11 +800,12 @@ type
deepCopy*: PSym # overriden 'deepCopy' operation
size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown
align*: int # the type's alignment requirements
align*: int16 # the type's alignment requirements
lockLevel*: TLockLevel # lock level as required for deadlock checking
loc*: TLoc
TPair*{.final.} = object
key*, val*: PObject
key*, val*: RootRef
TPairSeq* = seq[TPair]
TTable*{.final.} = object # the same as table[PObject] of PObject
@ -811,7 +814,7 @@ type
TIdPair*{.final.} = object
key*: PIdObj
val*: PObject
val*: RootRef
TIdPairSeq* = seq[TIdPair]
TIdTable*{.final.} = object # the same as table[PIdent] of PObject
@ -838,7 +841,7 @@ type
counter*: int
data*: TNodePairSeq
TObjectSeq* = seq[PObject]
TObjectSeq* = seq[RootRef]
TObjectSet*{.final.} = object
counter*: int
data*: TObjectSeq
@ -1054,7 +1057,7 @@ proc discardSons(father: PNode) =
father.sons = nil
when defined(useNodeIds):
const nodeIdToDebug* = 310841 # 612794
const nodeIdToDebug* = -1 # 884953 # 612794
#612840 # 612905 # 614635 # 614637 # 614641
# 423408
#429107 # 430443 # 441048 # 441090 # 441153
@ -1166,6 +1169,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body]
const
UnspecifiedLockLevel* = TLockLevel(-1'i16)
MaxLockLevel* = 1000'i16
UnknownLockLevel* = TLockLevel(1001'i16)
proc `$`*(x: TLockLevel): string =
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
else: result = $int16(x)
proc newType(kind: TTypeKind, owner: PSym): PType =
new(result)
result.kind = kind
@ -1173,6 +1186,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
result.size = - 1
result.align = 2 # default alignment
result.id = getID()
result.lockLevel = UnspecifiedLockLevel
when debugIds:
registerId(result)
#if result.id < 2000:
@ -1184,7 +1198,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
a.flags = a.flags + b.flags
if a.t == nil: a.t = b.t
if a.r == nil: a.r = b.r
if a.a == 0: a.a = b.a
#if a.a == 0: a.a = b.a
proc assignType(dest, src: PType) =
dest.kind = src.kind
@ -1195,6 +1209,7 @@ proc assignType(dest, src: PType) =
dest.align = src.align
dest.destructor = src.destructor
dest.deepCopy = src.deepCopy
dest.lockLevel = src.lockLevel
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:
@ -1545,3 +1560,9 @@ proc isEmptyType*(t: PType): bool {.inline.} =
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
result = t == nil or t.kind in {tyEmpty, tyStmt}
proc makeStmtList*(n: PNode): PNode =
if n.kind == nkStmtList:
result = n
else:
result = newNodeI(nkStmtList, n.info)
result.add n

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -14,7 +14,7 @@
import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
proc hashNode*(p: PObject): THash
proc hashNode*(p: RootRef): THash
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
# Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes.
@ -24,21 +24,21 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
proc lineInfoToStr*(info: TLineInfo): PRope
# ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
# returns true whether n is in t
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
# include an element n in the table t
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
# more are not needed ...
# ----------------------- (key, val)-Hashtables ----------------------------
proc tablePut*(t: var TTable, key, val: PObject)
proc tableGet*(t: TTable, key: PObject): PObject
proc tablePut*(t: var TTable, key, val: RootRef)
proc tableGet*(t: TTable, key: RootRef): RootRef
type
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
proc tableSearch*(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject
proc tableSearch*(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef
# return val as soon as comparator returns true; if this never happens,
# nil is returned
@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.}
proc debug*(n: PNode) {.deprecated.}
# --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
proc idTableGet*(t: TIdTable, key: int): PObject
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
proc idTableGet*(t: TIdTable, key: int): RootRef
proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id)
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
else: internalError(list.info, "getSymFromList")
result = nil
proc hashNode(p: PObject): THash =
proc hashNode(p: RootRef): THash =
result = hash(cast[pointer](p))
proc mustRehash(length, counter: int): bool =
@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope =
toRope(toLinenumber(info)),
toRope(toColumn(info))])
proc treeToYamlAux(n: PNode, marker: var TIntSet,
proc treeToYamlAux(n: PNode, marker: var IntSet,
indent, maxRecDepth: int): PRope
proc symToYamlAux(n: PSym, marker: var TIntSet,
proc symToYamlAux(n: PSym, marker: var IntSet,
indent, maxRecDepth: int): PRope
proc typeToYamlAux(n: PType, marker: var TIntSet,
proc typeToYamlAux(n: PType, marker: var IntSet,
indent, maxRecDepth: int): PRope
proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
maxRecDepth: int): PRope =
var istr = spaces(indent + 2)
result = toRope("[")
@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
inc(i, 2)
appf(result, "$N$1}", [spaces(indent)])
proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
else:
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
result = ropeConstr(indent, [toRope("kind"),
@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
flagsToStr(n.options), toRope("position"),
toRope(n.position)])
proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
else:
if sonsLen(n) > 0:
result = toRope("[")
@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
toRope("align"), toRope(n.align),
toRope("sons"), result])
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): PRope =
if n == nil:
result = toRope("null")
@ -450,9 +450,10 @@ proc debug(n: PSym) =
writeln(stdout, "skUnknown")
else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
writeln(stdout, "$1_$2: $3, $4, $5, $6" % [
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
$n.kind])
proc debug(n: PType) =
writeln(stdout, ropeToStr(debugType(n)))
@ -469,7 +470,7 @@ proc nextTry(h, maxHash: THash): THash =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil:
@ -478,7 +479,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool =
h = nextTry(h, high(t.data))
result = false
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
var h: THash = hashNode(obj) and high(data)
while data[h] != nil:
assert(data[h] != obj)
@ -493,12 +494,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n)
proc objectSetIncl(t: var TObjectSet, obj: PObject) =
proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj)
inc(t.counter)
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
# returns true if obj is already in the string table:
var h: THash = hashNode(obj) and high(t.data)
while true:
@ -516,7 +517,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
inc(t.counter)
result = false
proc tableRawGet(t: TTable, key: PObject): int =
proc tableRawGet(t: TTable, key: RootRef): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
@ -524,8 +525,8 @@ proc tableRawGet(t: TTable, key: PObject): int =
h = nextTry(h, high(t.data))
result = -1
proc tableSearch(t: TTable, key, closure: PObject,
comparator: TCmpProc): PObject =
proc tableSearch(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
@ -535,12 +536,12 @@ proc tableSearch(t: TTable, key, closure: PObject,
h = nextTry(h, high(t.data))
result = nil
proc tableGet(t: TTable, key: PObject): PObject =
proc tableGet(t: TTable, key: RootRef): RootRef =
var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
var h: THash = hashNode(key) and high(data)
while data[h].key != nil:
assert(data[h].key != key)
@ -556,7 +557,7 @@ proc tableEnlarge(t: var TTable) =
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc tablePut(t: var TTable, key, val: PObject) =
proc tablePut(t: var TTable, key, val: RootRef) =
var index = tableRawGet(t, key)
if index >= 0:
t.data[index].val = val
@ -626,20 +627,34 @@ proc strTableAdd(t: var TStrTable, n: PSym) =
strTableRawInsert(t.data, n)
inc(t.counter)
proc reallySameIdent(a, b: string): bool {.inline.} =
when defined(nimfix):
result = a[0] == b[0]
else:
result = true
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
# returns true if n is already in the string table:
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
assert n.name != nil
var h: THash = n.name.h and high(t.data)
var replaceSlot = -1
while true:
var it = t.data[h]
if it == nil: break
if it.name.id == n.name.id:
t.data[h] = n # overwrite it with newer definition!
return true # found it
# Semantic checking can happen multiple times thanks to templates
# and overloading: (var x=@[]; x).mapIt(it).
# So it is possible the very same sym is added multiple
# times to the symbol table which we allow here with the 'it == n' check.
if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s):
if it == n: return false
replaceSlot = h
h = nextTry(h, high(t.data))
if mustRehash(len(t.data), t.counter):
if replaceSlot >= 0:
t.data[replaceSlot] = n # overwrite it with newer definition!
return true # found it
elif mustRehash(len(t.data), t.counter):
strTableEnlarge(t)
strTableRawInsert(t.data, n)
else:
@ -677,7 +692,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
ti.h = nextTry(h, high(tab.data))
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: TIntSet): PSym =
excluding: IntSet): PSym =
var h: THash = ti.h and high(tab.data)
var start = h
result = tab.data[h]
@ -693,7 +708,7 @@ proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
if result != nil and contains(excluding, result.id): result = nil
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: TIntSet): PSym =
excluding: IntSet): PSym =
ti.h = s.h
ti.name = s
if tab.counter == 0: result = nil
@ -740,22 +755,22 @@ proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
if index >= 0: result = t.data[index].key == key
else: result = false
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
proc idTableGet(t: TIdTable, key: int): PObject =
proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
for i in 0..high(t.data):
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: THash
h = key.id and high(data)
while data[h].key != nil:
@ -765,7 +780,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
data[h].key = key
data[h].val = val
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
var
index: int
n: TIdPairSeq
@ -784,7 +799,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
idTableRawInsert(t.data, key, val)
inc(t.counter)
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)

View file

@ -1,14 +1,14 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# this unit handles Nimrod sets; it implements bit sets
# the code here should be reused in the Nimrod standard library
# this unit handles Nim sets; it implements bit sets
# the code here should be reused in the Nim standard library
type
TBitSet* = seq[int8] # we use byte here to avoid issues with

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -370,7 +370,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nimrod's heavy compile-time evaluation features
# it is not necessary, but Nim's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -103,9 +103,9 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
result = ropef("$1, $1Len0", [rdLoc(a)])
of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar:
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField()])
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
else:
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: internalError("openArrayLoc: " & typeToString(a.t))

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -11,11 +11,19 @@
# -------------------------- constant expressions ------------------------
proc int64Literal(i: BiggestInt): PRope =
if i > low(int64):
result = rfmt(nil, "IL64($1)", toRope(i))
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
proc intLiteral(i: BiggestInt): PRope =
if (i > low(int32)) and (i <= high(int32)):
if i > low(int32) and i <= high(int32):
result = toRope(i)
elif i == low(int32):
# Nimrod has the same bug for the same reasons :-)
# Nim has the same bug for the same reasons :-)
result = ~"(-2147483647 -1)"
elif i > low(int64):
result = rfmt(nil, "IL64($1)", toRope(i))
@ -31,7 +39,7 @@ proc int32Literal(i: int): PRope =
proc genHexLiteral(v: PNode): PRope =
# hex literals are unsigned in C
# so we don't generate hex literals any longer.
if not (v.kind in {nkIntLit..nkUInt64Lit}):
if v.kind notin {nkIntLit..nkUInt64Lit}:
internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal)
@ -46,16 +54,18 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
case n.kind
of nkCharLit..nkUInt64Lit:
case skipTypes(ty, abstractVarRange).kind
of tyChar, tyInt64, tyNil:
of tyChar, tyNil:
result = intLiteral(n.intVal)
of tyInt:
if (n.intVal >= low(int32)) and (n.intVal <= high(int32)):
if n.intVal >= low(int32) and n.intVal <= high(int32):
result = int32Literal(int32(n.intVal))
else:
result = intLiteral(n.intVal)
of tyBool:
if n.intVal != 0: result = ~"NIM_TRUE"
else: result = ~"NIM_FALSE"
of tyInt64: result = int64Literal(n.intVal)
of tyUInt64: result = uint64Literal(uint64(n.intVal))
else:
result = ropef("(($1) $2)", [getTypeDesc(p.module,
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
@ -214,9 +224,9 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let newflags =
if src.k == locData:
flags + { needToCopy }
flags + {needToCopy}
elif tfShallow in dest.t.flags:
flags - { needToCopy }
flags - {needToCopy}
else:
flags
for i in 0 .. <dest.t.len:
@ -230,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
if t == nil: return
let newflags =
if src.k == locData:
flags + { needToCopy }
flags + {needToCopy}
elif tfShallow in dest.t.flags:
flags - { needToCopy }
flags - {needToCopy}
else:
flags
case t.kind
@ -318,7 +328,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyObject:
# XXX: check for subtyping?
if needsComplexAssignment(ty):
if not isObjLackingTypeField(ty):
genGenericAsgn(p, dest, src, flags)
elif needsComplexAssignment(ty):
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
discard getTypeDesc(p.module, ty)
internalAssert ty.n != nil
@ -409,7 +421,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
d.k = locData
d.t = getUniqueType(t)
d.r = r
d.a = -1
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
var a: TLoc
@ -425,7 +436,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
d.k = locExpr
d.t = getUniqueType(t)
d.r = r
d.a = -1
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
@ -647,13 +657,16 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)]))
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}:
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
let mt = mapType(e.sons[0].typ)
if mt in {ctArray, ctPtrToArray} and not enforceDeref:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
#if e[0].kind != nkBracketExpr:
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
expr(p, e.sons[0], d)
else:
var a: TLoc
initLocExpr(p, e.sons[0], a)
case skipTypes(a.t, abstractInst).kind
of tyRef:
@ -663,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
of tyPtr:
d.s = OnUnknown # BUGFIX!
else: internalError(e.info, "genDeref " & $a.t.kind)
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
if enforceDeref and mt == ctPtrToArray:
# we lie about the type for better C interop: 'ptr array[3,T]' is
# translated to 'ptr T', but for deref'ing this produces wrong code.
# See tmissingderef. So we get rid of the deref instead. The codegen
# ends up using 'memcpy' for the array assignment,
# so the '&' and '*' cancel out:
putIntoDest(p, d, a.t.sons[0], rdLoc(a))
else:
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
@ -723,7 +744,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
internalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
if not p.module.compileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
@ -775,7 +796,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
assert(ty.kind in {tyTuple, tyObject})
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
if not p.module.compileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genCheckedRecordField")
if field.loc.r == nil:
@ -786,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
else:
genRecordField(p, e.sons[0], d)
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
initLocExpr(p, x, a)
initLocExpr(p, y, b)
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
var first = intLiteral(firstOrd(ty))
# emit range check:
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
if not isConstExpr(e.sons[1]):
if not isConstExpr(y):
# semantic pass has already checked for const index expressions
if firstOrd(ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
@ -804,26 +825,26 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
rdCharLoc(b), first, intLiteral(lastOrd(ty)))
else:
let idx = getOrdValue(e.sons[1])
let idx = getOrdValue(y)
if idx < firstOrd(ty) or idx > lastOrd(ty):
localError(e.info, errIndexOutOfBounds)
localError(x.info, errIndexOutOfBounds)
d.inheritLocation(a)
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
initLocExpr(p, x, a)
initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) # emit range check:
initLocExpr(p, x, a)
initLocExpr(p, y, b) # emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
@ -831,10 +852,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
initLocExpr(p, x, a)
initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
@ -842,11 +863,11 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
if ty.kind == tyString:
linefmt(p, cpsStmts,
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField())
rdLoc(b), rdLoc(a), lenField(p))
else:
linefmt(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField())
rdLoc(b), rdLoc(a), lenField(p))
if d.k == locNone: d.s = OnHeap
d.heapRoot = a.r
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
@ -854,6 +875,17 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
of tyTuple: genTupleElem(p, n, d)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# how to generate code?
# 'expr1 and expr2' becomes:
@ -895,20 +927,21 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe.
internalAssert n.kind == nkBracket
discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
var args: PRope = nil
var a: TLoc
for i in countup(1, n.len-1):
for i in countup(0, n.len-1):
initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeatStr(n.len-1, "%s") & tnl), args)
makeCString(repeatStr(n.len, "%s") & tnl), args)
proc gcUsage(n: PNode) =
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
# <Nim code>
# s = 'Hello ' & name & ', how do you feel?' & 'z'
#
# <generated C code>
@ -939,7 +972,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
app(p.s(cpsStmts), appends)
@ -951,7 +984,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
gcUsage(e)
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
# <Nim code>
# s &= 'Hello ' & name & ', how do you feel?' & 'z'
# // BUG: what if s is on the left side too?
# <generated C code>
@ -979,7 +1012,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
app(appends, rfmt(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
@ -992,7 +1025,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = x;
let seqAppendPattern = if gCmd != cmdCompileToCpp:
let seqAppendPattern = if not p.module.compileToCpp:
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
@ -1005,7 +1038,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
keepAlive(p, a)
initLoc(dest, locExpr, b.t, OnHeap)
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField())
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p))
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
gcUsage(e)
@ -1099,11 +1132,11 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
while ty != nil:
field = lookupInRecord(ty.n, it.sons[0].sym.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
if not p.module.compileToCpp: app(tmp2.r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options:
genFieldCheck(p, it.sons[2], r, field)
genFieldCheck(p, it.sons[2], tmp2.r, field)
app(tmp2.r, ".")
app(tmp2.r, field.loc.r)
tmp2.k = locTemp
@ -1200,8 +1233,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
if t.kind != tyVar: nilCheck = r
r = rfmt(nil, "(*$1)", r)
t = skipTypes(t.lastSon, typedescInst)
if gCmd != cmdCompileToCpp:
while (t.kind == tyObject) and (t.sons[0] != nil):
if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
app(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst)
if isObjLackingTypeField(t):
@ -1246,7 +1279,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
of tyString, tySequence:
putIntoDest(p, b, e.typ,
ropef("$1->data, $1->$2", [rdLoc(a), lenField()]))
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ,
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
@ -1289,7 +1322,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
else: unaryExpr(p, e, d, "strlen($1)")
of tyString, tySequence:
if gCmd != cmdCompileToCpp:
if not p.module.compileToCpp:
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
else: unaryExpr(p, e, d, "$1->Sup.len")
else:
@ -1307,7 +1340,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar)
let setLenPattern = if gCmd != cmdCompileToCpp:
let setLenPattern = if not p.module.compileToCpp:
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
else:
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
@ -1508,7 +1541,6 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
tmp.k = locExpr
tmp.a = -1
tmp.t = srct
tmp.s = OnStack
tmp.flags = {}
@ -1564,11 +1596,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e.typ,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e.typ,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")
@ -1673,7 +1705,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
discard cgsym(p.module, opr.loc.r.ropeToStr)
genCall(p, e, d)
of mReset: genReset(p, e)
of mEcho: genEcho(p, e)
of mEcho: genEcho(p, e[1].skipConv)
of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError:
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
@ -1695,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
proc genConstExpr(p: BProc, n: PNode): PRope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
@ -1827,7 +1859,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
if t.kind != tyVar: nilCheck = r
r = ropef("(*$1)", [r])
t = skipTypes(t.lastSon, abstractInst)
if gCmd != cmdCompileToCpp:
if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst)
@ -1845,22 +1877,38 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
[getTypeDesc(p.module, dest), addrLoc(a)]))
proc downConv(p: BProc, n: PNode, d: var TLoc) =
if gCmd == cmdCompileToCpp:
if p.module.compileToCpp:
expr(p, n.sons[0], d) # downcast does C++ for us
else:
var dest = skipTypes(n.typ, abstractPtrs)
var src = skipTypes(n.sons[0].typ, abstractPtrs)
var arg = n.sons[0]
while arg.kind == nkObjDownConv: arg = arg.sons[0]
var src = skipTypes(arg.typ, abstractPtrs)
var a: TLoc
initLocExpr(p, n.sons[0], a)
initLocExpr(p, arg, a)
var r = rdLoc(a)
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and
n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}:
let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
if isRef:
app(r, "->Sup")
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
r = con("&", r)
else:
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
putIntoDest(p, d, n.typ, r)
app(r, ".Sup")
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
if isRef:
# it can happen that we end up generating '&&x->Sup' here, so we pack
# the '&x->Sup' into a temporary and then those address is taken
# (see bug #837). However sometimes using a temporary is not correct:
# init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
# this by ensuring the destination is also a pointer:
if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
getTemp(p, n.typ, d)
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
else:
r = con("&", r)
putIntoDest(p, d, n.typ, r)
else:
putIntoDest(p, d, n.typ, r)
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
@ -1978,16 +2026,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkCast: genCast(p, n, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
of nkHiddenAddr, nkAddr: genAddr(p, n, d)
of nkBracketExpr:
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr: genArrayElem(p, n, d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d)
of tySequence, tyString: genSeqElem(p, n, d)
of tyCString: genCStringElem(p, n, d)
of tyTuple: genTupleElem(p, n, d)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
of nkBracketExpr: genBracketExpr(p, n, d)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d)
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
@ -2031,7 +2070,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[0], a)
of nkAsmStmt: genAsmStmt(p, n)
of nkTryStmt:
if gCmd == cmdCompileToCpp: genTryCpp(p, n, d)
if p.module.compileToCpp: genTryCpp(p, n, d)
else: genTry(p, n, d)
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection:
@ -2043,6 +2082,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
nkFromStmt, nkTemplateDef, nkMacroDef:
discard
of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d)
of nkProcDef, nkMethodDef, nkConverterDef:
if (n.sons[genericParamsPos].kind == nkEmpty):
var prc = n.sons[namePos].sym

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -83,7 +83,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
inc i
s.add('}')
proc writeIntSet(a: TIntSet, s: var string) =
proc writeIntSet(a: IntSet, s: var string) =
var i = 0
for x in items(a):
if i == 10:
@ -200,7 +200,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
idTablePut(result, newFakeType(key), value.toRope)
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
@ -249,7 +249,7 @@ proc readMergeInfo*(cfilename: string, m: BModule) =
break
type
TMergeSections = object {.pure.}
TMergeSections = object
f: TCFileSections
p: TCProcSections

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) =
if useLowering:
genStmts(p, lowerTupleUnpacking(n, p.prc))
return
genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup)
var t = tup.t
@ -69,10 +68,21 @@ proc genVarTuple(p: BProc, n: PNode) =
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
ri.sons[0].sym.magic == mNone):
genAsgnCall(p, le, ri, a)
elif ri.kind in {nkDerefExpr, nkHiddenDeref}:
# this is a hacky way to fix #1181 (tmissingderef)::
#
# var arr1 = cast[ptr array[4, int8]](addr foo)[]
#
# However, fixing this properly really requires modelling 'array' as
# a 'struct' in C to preserve dereferencing semantics completely. Not
# worth the effort until version 1.0 is out.
genDeref(p, ri, a, enforceDeref=true)
else:
expr(p, ri, a)
@ -294,8 +304,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
var alreadyPoppedCnt = p.inExceptBlock
for i in countup(1, howManyTrys):
if gCmd != cmdCompileToCpp:
if not p.module.compileToCpp:
# Pop safe points generated by try
if alreadyPoppedCnt > 0:
dec alreadyPoppedCnt
@ -317,7 +326,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if gCmd != cmdCompileToCpp:
if not p.module.compileToCpp:
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
@ -448,7 +457,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym
sym.loc.k = locOther
sym.loc.a = p.breakIdx
sym.position = p.breakIdx+1
expr(p, t.sons[1], d)
endBlock(p)
@ -487,7 +496,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym
assert(sym.loc.k == locOther)
idx = sym.loc.a
idx = sym.position-1
else:
# an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
@ -501,8 +510,10 @@ proc genBreakStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string =
if gCmd == cmdCompileToCpp:
if p.module.compileToCpp:
result = "throw NimException($1, $2);$n"
elif getCompilerProc("Exception") != nil:
result = "#raiseException((#Exception*)$1, $2);$n"
else:
result = "#raiseException((#E_Base*)$1, $2);$n"
@ -520,10 +531,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t)
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
else:
else:
genLineDir(p, t)
# reraise the last exception:
if gCmd == cmdCompileToCpp:
if p.module.compileToCpp:
line(p, cpsStmts, ~"throw;$n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n")
@ -559,7 +570,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr,
until: int, a: TLoc): TLabel =
# generate a C-if statement for a Nimrod case statement
# generate a C-if statement for a Nim case statement
var labId = p.labels
for i in 1..until:
inc(p.labels)
@ -747,7 +758,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
i, length, blen: int
genLineDir(p, t)
exc = getTempName()
discard cgsym(p.module, "E_Base")
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
discard cgsym(p.module, "E_Base")
add(p.nestedTryStmts, t)
startBlock(p, "try {$n")
expr(p, t.sons[0], d)
@ -784,7 +798,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
startBlock(p)
var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally:
expr(p, finallyBlock.sons[0], d)
#expr(p, finallyBlock.sons[0], d)
genStmts(p, finallyBlock.sons[0])
line(p, cpsStmts, ~"throw;$n")
endBlock(p)
@ -793,7 +809,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.nestedTryStmts)
if (i < length) and (t.sons[i].kind == nkFinally):
exprBlock(p, t.sons[i].sons[0], d)
genSimpleBlock(p, t.sons[i].sons[0])
proc genTry(p: BProc, t: PNode, d: var TLoc) =
# code to generate:
@ -829,7 +845,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName()
discard cgsym(p.module, "E_Base")
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
discard cgsym(p.module, "E_Base")
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
if isDefined("nimStdSetjmp"):
@ -882,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally:
p.finallySafePoints.add(safePoint)
exprBlock(p, t.sons[i].sons[0], d)
genSimpleBlock(p, t.sons[i].sons[0])
discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -57,6 +57,9 @@ proc generateThreadLocalStorage(m: BModule) =
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
app(m.s[cfsProcs],
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)
let externc = if gCmd != cmdCompileToCpp and
sfCompileToCpp in m.module.flags: "extern \"C\""
else: ""
appf(m.s[cfsProcs],
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
[externc.toRope])

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -49,8 +49,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
else: internalError(n.info, "genTraverseProc()")
proc parentObj(accessor: PRope): PRope {.inline.} =
if gCmd != cmdCompileToCpp:
proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
if not m.compileToCpp:
result = ropef("$1.Sup", accessor)
else:
result = accessor
@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
lineF(p, cpsStmts, "}$n")
of tyObject:
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj, typ.sons[i])
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple:
let typ = getUniqueType(typ)
@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var i: TLoc
getTemp(p, getSysType(tyInt), i)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
lineF(p, cpsStmts, "}$n")

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -162,10 +162,14 @@ proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
else: result = mapType(typ)
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ)
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.sons[0] == nil) or isPureObject(typ))
proc isInvalidReturnType(rettype: PType): bool =
# Arrays and sets cannot be returned by a C procedure, because C is
# such a poor programming language.
@ -177,10 +181,12 @@ proc isInvalidReturnType(rettype: PType): bool =
of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyRef, tyPtr})
of ctStruct:
result = needsComplexAssignment(skipTypes(rettype, typedescInst))
of ctStruct:
let t = skipTypes(rettype, typedescInst)
result = needsComplexAssignment(t) or
(t.kind == tyObject and not isObjLackingTypeField(t))
else: result = false
const
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
"N_STDCALL", "N_CDECL", "N_SAFECALL",
@ -228,7 +234,7 @@ proc fillResult(param: PSym) =
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope =
when false:
if t.Kind in {tyRef, tyPtr, tyVar}:
var b = skipTypes(t.lastson, typedescInst)
@ -243,7 +249,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
result = OnUnknown
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
check: var TIntSet, declareEnvironment=true) =
check: var IntSet, declareEnvironment=true) =
params = nil
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
rettype = ~"void"
@ -330,7 +336,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
of tyDistinct, tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil
proc getTypePre(m: BModule, typ: PType): PRope =
@ -342,8 +348,8 @@ proc getTypePre(m: BModule, typ: PType): PRope =
proc structOrUnion(t: PType): PRope =
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
proc getForwardStructFormat(): string =
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
proc getForwardStructFormat(m: BModule): string =
if m.compileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n"
proc getTypeForward(m: BModule, typ: PType): PRope =
@ -355,7 +361,7 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
of tySequence, tyTuple, tyObject:
result = getTypeName(typ)
if not isImportedType(typ):
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')')
@ -370,7 +376,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: PRope, rectype: PType,
check: var TIntSet): PRope =
check: var IntSet): PRope =
var
ae, uname, sname, a: PRope
k: PNode
@ -419,19 +425,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
proc getRecordDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
check: var IntSet): PRope =
# declare the record:
var hasField = false
var attribute: PRope =
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
else: nil
result = ropecg(m, CC[ccompiler].structStmtFmt,
result = ropecg(m, CC[cCompiler].structStmtFmt,
[structOrUnion(typ), name, attribute])
if typ.kind == tyObject:
@ -442,7 +448,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
hasField = true
elif gCmd == cmdCompileToCpp:
elif m.compileToCpp:
appcg(m, result, " : public $1 {$n",
[getTypeDescAux(m, typ.sons[0], check)])
hasField = true
@ -461,7 +467,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
app(result, "};" & tnl)
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
check: var TIntSet): PRope =
check: var IntSet): PRope =
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
var desc: PRope = nil
for i in countup(0, sonsLen(typ) - 1):
@ -474,7 +480,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope,
proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ)
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
# returns only the type's name
var
name, rettype, desc, recdesc: PRope
@ -538,7 +544,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
assert(cacheGetType(m.typeCache, t) == nil)
@ -550,7 +556,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
cSeq = "struct $2 {$n" &
" #TGenericSeq Sup;$n"
appcg(m, m.s[cfsSeqTypes],
(if gCmd == cmdCompileToCpp: cppSeq else: cSeq) &
(if m.compileToCpp: cppSeq else: cSeq) &
" $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
else:
@ -570,7 +576,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
if result == nil:
result = getTypeName(t)
if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result)
idTablePut(m.typeCache, t, result) # always call for sideeffects:
@ -678,10 +684,6 @@ when false:
var tmp = getNimType(m)
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.sons[0] == nil) or isPureObject(typ))
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
var nimtypeKind: int
#allocMemTI(m, typ, name)
@ -898,7 +900,7 @@ include ccgtrav
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
genProc(m, s)
appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n",
appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r])
proc genTypeInfo(m: BModule, t: PType): PRope =

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -149,7 +149,7 @@ proc getUniqueType*(key: PType): PType =
idTablePut(gTypeTable[k], key, key)
result = key
proc tableGetType*(tab: TIdTable, key: PType): PObject =
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
# returns nil if we need to declare this type
result = idTableGet(tab, key)
if (result == nil) and (tab.counter > 0):
@ -171,7 +171,7 @@ proc mangle*(name: string): string =
## Lowercases the given name and manges any non-alphanumeric characters
## so they are represented as `HEX____`. If the name starts with a number,
## `N` is prepended
result = ""
result = newStringOfCap(name.len)
case name[0]
of Letters:
result.add(name[0].toLower)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -55,7 +55,6 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.s = s
result.t = getUniqueType(typ)
result.r = nil
result.a = - 1
result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
@ -63,7 +62,6 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
if a.k == locNone:
a.k = k
a.t = getUniqueType(typ)
a.a = - 1
a.s = s
if a.r == nil: a.r = r
@ -139,7 +137,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
if i - 1 >= start:
app(result, substr(frmt, start, i - 1))
const compileTimeRopeFmt = not defined(booting)
const compileTimeRopeFmt = false
when compileTimeRopeFmt:
import macros
@ -186,7 +184,7 @@ when compileTimeRopeFmt:
while s[i] in IdentChars: inc i
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
start = i
else: nil
else: discard
while i < length:
if s[i] != '$' and s[i] != '#': inc i
@ -201,7 +199,7 @@ when compileTimeRopeFmt:
## the compilation of nimrod itself or will the macro execution time
## offset the gains?
result = newCall(bindSym"ropeConcat")
for frag in fmtStringFragments(fmt.strVal):
for frag in fmtStringFragments(fmt):
case frag.kind
of ffSym:
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
@ -286,7 +284,7 @@ proc genLineDir(p: BProc, t: PNode) =
line.toRope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags):
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename)
@ -297,6 +295,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.}
proc genProc(m: BModule, prc: PSym)
template compileToCpp(m: BModule): expr =
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
include "ccgtypes.nim"
# ------------------------------ Manager of temporaries ------------------
@ -309,7 +310,7 @@ proc rdLoc(a: TLoc): PRope =
proc addrLoc(a: TLoc): PRope =
result = a.r
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
result = con("&", result)
result = con("(&", result).con(")")
proc rdCharLoc(a: TLoc): PRope =
# read a location that may need a char-cast:
@ -326,7 +327,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
var r = rdLoc(a)
if not takeAddr: r = ropef("(*$1)", [r])
var s = skipTypes(t, abstractInst)
if gCmd != cmdCompileToCpp:
if not p.module.compileToCpp:
while (s.kind == tyObject) and (s.sons[0] != nil):
app(r, ".Sup")
s = skipTypes(s.sons[0], abstractInst)
@ -407,7 +408,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
result.r = con("LOC", toRope(p.labels))
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp
result.a = - 1
#result.a = - 1
result.t = getUniqueType(t)
result.s = OnStack
result.flags = {}
@ -425,7 +426,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
[getTypeDesc(p.module, toKeepAlive.t), fid])
inc(p.gcFrameId)
result.k = locTemp
result.a = -1
#result.a = -1
result.t = toKeepAlive.t
result.s = OnStack
result.flags = {}
@ -505,9 +506,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags or (p.nestedTryStmts.len > 0 and
gCmd != cmdCompileToCpp):
app(decl, " volatile")
if sfVolatile in s.flags: app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
@ -587,8 +586,8 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown)
expr(p, e, result)
proc lenField: PRope {.inline.} =
result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")
proc lenField(p: BProc): PRope =
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
@ -812,7 +811,12 @@ proc genProcAux(m: BModule, prc: PSym) =
app(generatedProc, returnStmt)
app(generatedProc, ~"}$N")
app(m.s[cfsProcs], generatedProc)
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
result = sfCompileToCpp in m.module.flags and
sfCompileToCpp notin sym.getModule().flags and
gCmd != cmdCompileToCpp
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags: return
@ -824,6 +828,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym)
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
header = con("extern \"C\" ", header)
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
header.app(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
@ -915,30 +921,30 @@ proc addIntTypes(result: var PRope) {.inline.} =
appf(result, "#define NIM_INTBITS $1", [
platform.CPU[targetCPU].intSize.toRope])
proc getCopyright(cfilenoext: string): PRope =
proc getCopyright(cfile: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; Generated by Nim Compiler v$1$N" &
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2014 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N",
"; Generated by Nimrod Compiler v$1$N" &
"; Generated by Nim Compiler v$1$N" &
"; (c) 2014 Andreas Rumpf$N" &
"; Compiled for: $2, $3, $4$N" &
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.cCompiler].name),
toRope(getCompileCFileCmd(cfilenoext))])
toRope(getCompileCFileCmd(cfile))])
proc getFileHeader(cfilenoext: string): PRope =
result = getCopyright(cfilenoext)
proc getFileHeader(cfile: string): PRope =
result = getCopyright(cfile)
addIntTypes(result)
proc genFilenames(m: BModule): PRope =
@ -963,7 +969,7 @@ proc genMainProc(m: BModule) =
"\tvoid (*volatile inner)();$N" &
"\tsystemDatInit();$N" &
"\tinner = PreMainInner;$N" &
"$4" &
"$4$5" &
"\t(*inner)();$N" &
"}$N$N"
@ -1051,12 +1057,16 @@ proc genMainProc(m: BModule) =
gBreakpoints.app(m.genFilenames)
let initStackBottomCall =
if emulatedThreadVars() or
platform.targetOS == osStandalone: "".toRope
if platform.targetOS == osStandalone: "".toRope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [
mainDatInit, gBreakpoints, otherModsInit, initStackBottomCall])
mainDatInit, gBreakpoints, otherModsInit,
if emulatedThreadVars() and platform.targetOS != osStandalone:
ropecg(m, "\t#initThreadVarsEmulation();$N")
else:
"".toRope,
initStackBottomCall])
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
if optNoMain notin gGlobalOptions:
@ -1078,9 +1088,9 @@ proc registerModuleToMain(m: PSym) =
var
init = m.getInitName
datInit = m.getDatInitName
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
"declare void $1() noinline$N", [init])
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
"declare void $1() noinline$N", [datInit])
if sfSystemModule notin m.flags:
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
@ -1092,7 +1102,7 @@ proc registerModuleToMain(m: PSym) =
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [initname])
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
@ -1135,7 +1145,7 @@ proc genInitCode(m: BModule) =
app(prc, deinitGCFrame(m.initProc))
appf(prc, "}$N$N")
prc.appff("N_NOINLINE(void, $1)(void) {$N",
prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit:
@ -1155,8 +1165,8 @@ proc genInitCode(m: BModule) =
(i.ord - '0'.ord).toRope, el)
app(m.s[cfsInitProc], ex)
proc genModule(m: BModule, cfilenoext: string): PRope =
result = getFileHeader(cfilenoext)
proc genModule(m: BModule, cfile: string): PRope =
result = getFileHeader(cfile)
result.app(genMergeInfo(m))
generateHeaders(m)
@ -1297,7 +1307,11 @@ proc writeHeader(m: BModule) =
writeRope(result, m.filename)
proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt)
let ext =
if m.compileToCpp: ".cpp"
elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
else: ".c"
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
assert optSymbolFiles in gGlobalOptions
@ -1326,10 +1340,10 @@ proc finishModule(m: BModule) =
dec(gForwardedProcsCounter, i)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
proc shouldRecompile(code: PRope, cfile: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfilenoext)
var objFile = toObjFile(cfile)
if writeRopeIfNotEqual(code, cfile): return
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
else:
@ -1354,26 +1368,26 @@ proc writeModule(m: BModule, pending: bool) =
app(m.s[cfsProcHeaders], mainModProcs)
generateThreadVarsSize(m)
var code = genModule(m, cfilenoext)
var code = genModule(m, cfile)
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.compileCCode(ropeToStr(code))
return
if shouldRecompile(code, cfile, cfilenoext):
addFileToCompile(cfilenoext)
if shouldRecompile(code, cfile):
addFileToCompile(cfile)
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
mergeFiles(cfile, m)
genInitCode(m)
finishTypeDescriptions(m)
var code = genModule(m, cfilenoext)
var code = genModule(m, cfile)
writeRope(code, cfile)
addFileToCompile(cfilenoext)
addFileToCompile(cfile)
elif not existsFile(toObjFile(cfilenoext)):
# Consider: first compilation compiles ``system.nim`` and produces
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:
addFileToCompile(cfilenoext)
addFileToCompile(cfile)
addFileToLink(cfilenoext)
@ -1385,9 +1399,9 @@ proc updateCachedModule(m: BModule) =
mergeFiles(cfile, m)
genInitCode(m)
finishTypeDescriptions(m)
var code = genModule(m, cfilenoext)
var code = genModule(m, cfile)
writeRope(code, cfile)
addFileToCompile(cfilenoext)
addFileToCompile(cfile)
addFileToLink(cfilenoext)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -62,7 +62,7 @@ type
frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to
prc*: PSym # the Nim proc that this C proc belongs to
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
@ -101,10 +101,10 @@ type
# without extension)
typeCache*: TIdTable # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types
declaredThings*: TIntSet # things we have declared in this .c file
declaredProtos*: TIntSet # prototypes we have declared in this .c file
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information
typeInfoMarker*: IntSet # needed for generating type information
initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before the init proc

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -155,7 +155,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
if not sameType(t2, t):
return true
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
for col in countup(1, sonsLen(a.typ) - 1):
if contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs)
@ -164,7 +164,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
if (d != high(int)):
return d
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
# we use shellsort here; fast and simple
var n = len(a)
var h = 1
@ -183,7 +183,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
a[j] = v
if h == 1: break
proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
var base = lastSon(methods[0].ast).sym
result = base
var paramLen = sonsLen(base.typ)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
wordrecg, parseutils, babelcmd, idents
wordrecg, parseutils, nimblecmd, idents, parseopt
# but some have deps to imported modules. Yay.
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
@ -43,7 +43,7 @@ type
TCmdLinePass* = enum
passCmd1, # first pass over the command line
passCmd2, # second pass over the command line
passPP # preprocessor called ProcessCommand()
passPP # preprocessor called processCommand()
proc processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
# implementation
const
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
const
@ -226,6 +226,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
of "patterns": result = contains(gOptions, optPatterns)
of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false): string =
@ -234,7 +235,9 @@ proc processPath(path: string, notRelativeToProj = false): string =
path
else:
options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
"nim", getPrefixDir(),
"lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName,
"projectpath", options.gProjectPath])
@ -280,14 +283,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "path", "p":
expectArg(switch, arg, pass, info)
addPath(processPath(arg), info)
of "babelpath":
if pass in {passCmd2, passPP} and not options.gNoBabelPath:
of "nimblepath", "babelpath":
# keep the old name for compat
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
expectArg(switch, arg, pass, info)
let path = processPath(arg, notRelativeToProj=true)
babelpath(path, info)
of "nobabelpath":
nimblePath(path, info)
of "nonimblepath", "nobabelpath":
expectNoArg(switch, arg, pass, info)
options.gNoBabelPath = true
options.gNoNimblePath = true
of "excludepath":
expectArg(switch, arg, pass, info)
let path = processPath(arg)
@ -307,8 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info)
options.docSeeSrcUrl = arg
of "mainmodule", "m":
expectArg(switch, arg, pass, info)
optMainModule = arg
discard "allow for backwards compatibility, but don't do anything"
of "define", "d":
expectArg(switch, arg, pass, info)
defineSymbol(arg)
@ -566,6 +569,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "none": idents.firstCharIsCS = false
else: localError(info, errGenerated,
"'partial' or 'none' expected, but found " & arg)
of "experimental":
expectNoArg(switch, arg, pass, info)
gExperimentalMode = true
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info)
@ -574,3 +580,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo)
var
arguments* = ""
# the arguments to be passed to the program that
# should be run
proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here
var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val
processSwitch(key, val, pass, gCmdLineInfo)
else:
processSwitch(p.key, p.val, pass, gCmdLineInfo)
proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool =
if argsCount == 0:
options.command = p.key
else:
if pass == passCmd1: options.commandArgs.add p.key
if argsCount == 1:
# support UNIX style filenames anywhere for portable build scripts:
options.gProjectName = unixToNativePath(p.key)
arguments = cmdLineRest(p)
result = true
inc argsCount

View file

@ -14,7 +14,7 @@ import
# We need to use a PStringTable here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: PStringTable
var gSymbols: StringTableRef
proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"
@ -41,12 +41,12 @@ proc countDefinedSymbols*(): int =
for key, val in pairs(gSymbols):
if val == "true": inc(result)
# For ease of bootstrapping, we keep there here and not in the global config
# For ease of bootstrapping, we keep them here and not in the global config
# file for now:
const
additionalSymbols = """
x86 itanium x8664
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS doslike hpux
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS hpux
mac
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
@ -88,6 +88,7 @@ proc initDefines*() =
defineSymbol("nimrequiresnimframe")
defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias")
defineSymbol("nimlocks")
# add platform specific symbols:
for c in low(CPU)..high(CPU):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 =
const
bufSize = 8000 # don't use 8K for the memory allocator!
var
bin: TFile
bin: File
result = InitCrc32
if not open(bin, filename):
return # not equal if file does not exist

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -23,7 +23,7 @@ type
id: int # for generating IDs
toc, section: TSections
indexValFilename: string
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
PDoc* = ref TDocumentor ## Alias to type less.
@ -41,6 +41,7 @@ proc compilerMsgHandler(filename: string, line, col: int,
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
of mwUnsupportedField: k = warnFieldXNotSupported
globalError(newLineInfo(filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} =
@ -55,7 +56,7 @@ proc parseRst(text, filename: string,
result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
new(result)
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
options.gConfigVars, filename, {roSupportRawDirective},
@ -374,11 +375,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol)
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
itemIDRope = toRope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
var seeSrcRope: PRope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
@ -413,7 +414,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary))
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
if not isVisible(nameNode): return
var
name = getName(d, nameNode)
@ -473,7 +474,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: discard
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
case n.kind
of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -26,7 +26,7 @@ proc close(p: PPassContext, n: PNode): PNode =
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
try:
generateIndex(g.doc)
except EIO:
except IOError:
discard
proc processNode(c: PPassContext, n: PNode): PNode =

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This file implements the FFI part of the evaluator for Nimrod code.
## This file implements the FFI part of the evaluator for Nim code.
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,14 +1,16 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# module for calling the different external C compilers
# some things are read in from the configuration file
# Module providing functions for calling the different external C compilers
# Uses some hard-wired facts about each C/C++ compiler, plus options read
# from a configuration file, to provide generalized procedures to compile
# nim files.
import
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
@ -59,6 +61,7 @@ type
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
proc name: TInfoCC {.compileTime.} = settings
# GNU C and C++ Compiler
compiler gcc:
result = (
name: "gcc",
@ -84,21 +87,24 @@ compiler gcc:
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasNakedAttribute})
# LLVM Frontend for GCC/G++
compiler llvmGcc:
result = gcc()
result = gcc() # Uses settings from GCC
result.name = "llvm_gcc"
result.compilerExe = "llvm-gcc"
result.cppCompiler = "llvm-g++"
result.buildLib = "llvm-ar rcs $libfile $objfiles"
# Clang (LLVM) C/C++ Compiler
compiler clang:
result = llvmGcc()
result = llvmGcc() # Uses settings from llvmGcc
result.name = "clang"
result.compilerExe = "clang"
result.cppCompiler = "clang++"
# Microsoft Visual C/C++ Compiler
compiler vcc:
result = (
name: "vcc",
@ -123,6 +129,7 @@ compiler vcc:
packedPragma: "#pragma pack(1)",
props: {hasCpp, hasAssume, hasNakedDeclspec})
# Intel C/C++ Compiler
compiler icl:
# Intel compilers try to imitate the native ones (gcc and msvc)
when defined(windows):
@ -134,6 +141,7 @@ compiler icl:
result.compilerExe = "icl"
result.linkerExe = "icl"
# Local C Compiler
compiler lcc:
result = (
name: "lcc",
@ -158,6 +166,7 @@ compiler lcc:
packedPragma: "", # XXX: not supported yet
props: {})
# Borland C Compiler
compiler bcc:
result = (
name: "bcc",
@ -182,6 +191,7 @@ compiler bcc:
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
# Digital Mars C Compiler
compiler dmc:
result = (
name: "dmc",
@ -206,6 +216,7 @@ compiler dmc:
packedPragma: "#pragma pack(1)",
props: {hasCpp})
# Watcom C Compiler
compiler wcc:
result = (
name: "wcc",
@ -230,6 +241,7 @@ compiler wcc:
packedPragma: "", # XXX: not supported yet
props: {hasCpp})
# Tiny C Compiler
compiler tcc:
result = (
name: "tcc",
@ -254,6 +266,7 @@ compiler tcc:
packedPragma: "", # XXX: not supported yet
props: {hasSwitchRange, hasComputedGoto})
# Pelles C Compiler
compiler pcc:
# Pelles C
result = (
@ -279,6 +292,7 @@ compiler pcc:
packedPragma: "", # XXX: not supported yet
props: {})
# Your C Compiler
compiler ucc:
result = (
name: "ucc",
@ -323,10 +337,7 @@ const
var
cCompiler* = ccGcc # the used compiler
cExt* = ".c" # extension of generated C/C++ files
# (can be changed to .cpp later)
gMixedMode*: bool # true if some module triggered C++ codegen
cIncludes*: seq[string] = @[] # directories to search for included files
cLibs*: seq[string] = @[] # directories to search for lib files
cLinkedLibs*: seq[string] = @[] # libraries to link
@ -342,7 +353,9 @@ var
compileOptions: string = ""
ccompilerpath: string = ""
proc nameToCC*(name: string): TSystemCC =
proc nameToCC*(name: string): TSystemCC =
## Returns the kind of compiler referred to by `name`, or ccNone
## if the name doesn't refer to any known compiler.
for i in countup(succ(ccNone), high(TSystemCC)):
if cmpIgnoreStyle(name, CC[i].name) == 0:
return i
@ -351,17 +364,18 @@ proc nameToCC*(name: string): TSystemCC =
proc getConfigVar(c: TSystemCC, suffix: string): string =
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
# for niminst support
let fullSuffix = (if gCmd == cmdCompileToCpp: ".cpp" & suffix else: suffix)
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
optCompileOnly notin gGlobalOptions:
let fullCCname = platform.CPU[targetCPU].name & '.' &
platform.OS[targetOS].name & '.' &
CC[c].name & suffix
CC[c].name & fullSuffix
result = getConfigVar(fullCCname)
if result.len == 0:
# not overriden for this cross compilation setting?
result = getConfigVar(CC[c].name & suffix)
result = getConfigVar(CC[c].name & fullSuffix)
else:
result = getConfigVar(CC[c].name & suffix)
result = getConfigVar(CC[c].name & fullSuffix)
proc setCC*(ccname: string) =
cCompiler = nameToCC(ccname)
@ -387,8 +401,6 @@ proc initVars*() =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
if gCmd == cmdCompileToCpp: cExt = ".cpp"
elif gCmd == cmdCompileToOC: cExt = ".m"
addCompileOption(getConfigVar(cCompiler, ".options.always"))
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0:
@ -397,9 +409,9 @@ proc initVars*() =
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(cfile, createSubDir)
proc toObjFile*(filenameWithoutExt: string): string =
proc toObjFile*(filename: string): string =
# Object file for compilation
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
result = changeFileExt(filename, CC[cCompiler].objExt)
proc addFileToCompile*(filename: string) =
appendStr(toCompile, filename)
@ -417,8 +429,12 @@ proc addFileToLink*(filename: string) =
prependStr(toLink, filename)
# BUGFIX: was ``appendStr``
proc execExternalProgram*(cmd: string) =
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
proc execExternalProgram*(cmd: string, prettyCmd = "") =
if optListCmd in gGlobalOptions or gVerbosity > 0:
if prettyCmd != "":
msgWriteln(prettyCmd)
else:
msgWriteln(cmd)
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
proc generateScript(projectFile: string, script: PRope) =
@ -487,7 +503,7 @@ proc getLinkOptions: string =
proc needsExeExt(): bool {.inline.} =
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
(platform.hostOS == osWindows)
(platform.hostOS == osWindows)
proc getCompilerExe(compiler: TSystemCC): string =
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
@ -497,6 +513,7 @@ proc getCompilerExe(compiler: TSystemCC): string =
proc getLinkerExe(compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: compiler.getCompilerExe
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
@ -507,11 +524,11 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and
ospNeedsPIC in platform.OS[targetOS].props:
ospNeedsPIC in platform.OS[targetOS].props:
add(options, ' ' & CC[c].pic)
var includeCmd, compilePattern: string
if not noAbsolutePaths():
if not noAbsolutePaths():
# compute include paths:
includeCmd = CC[c].includeCmd & quoteShell(libpath)
@ -519,29 +536,31 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
compilePattern = joinPath(ccompilerpath, exe)
else:
else:
includeCmd = ""
compilePattern = c.getCompilerExe
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
else: cfilename
var objfile = if not isExternal or noAbsolutePaths():
toObjFile(cfile)
else:
var objfile = if not isExternal or noAbsolutePaths():
toObjFile(cfile)
else:
completeCFilePath(toObjFile(cfile))
cfile = quoteShell(addFileExt(cfile, cExt))
objfile = quoteShell(objfile)
result = quoteShell(compilePattern % [
"file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
"file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(),
"nim", getPrefixDir(), "lib", libpath])
add(result, ' ')
addf(result, CC[c].compileTmpl, [
"file", cfile, "objfile", objfile,
"options", options, "include", includeCmd,
"nimrod", quoteShell(getPrefixDir()),
"file", cfile, "objfile", objfile,
"options", options, "include", includeCmd,
"nimrod", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
proc footprint(filename: string): TCrc32 =
# note, '><' further modifies a crc value with a string.
result = crcFromFile(filename) ><
platform.OS[targetOS].name ><
platform.CPU[targetCPU].name ><
@ -551,7 +570,7 @@ proc footprint(filename: string): TCrc32 =
proc externalFileChanged(filename: string): bool =
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
var currentCrc = int(footprint(filename))
var f: TFile
var f: File
if open(f, crcFile, fmRead):
var line = newStringOfCap(40)
if not f.readLine(line): line = "0"
@ -569,14 +588,16 @@ proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename)
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
isExternal: bool) =
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
prettyCmds: var TStringSeq, isExternal: bool) =
var it = PStrEntry(list.head)
while it != nil:
inc(fileCounter) # call the C compiler for the .c file:
var compileCmd = getCompileCFileCmd(it.data, isExternal)
if optCompileOnly notin gGlobalOptions:
add(cmds, compileCmd)
let (dir, name, ext) = splitFile(it.data)
add(prettyCmds, "CC: " & name)
if optGenScript in gGlobalOptions:
app(script, compileCmd)
app(script, tnl)
@ -592,18 +613,24 @@ proc callCCompiler*(projectfile: string) =
var c = cCompiler
var script: PRope = nil
var cmds: TStringSeq = @[]
compileCFile(toCompile, script, cmds, false)
compileCFile(externalToCompile, script, cmds, true)
var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
compileCFile(toCompile, script, cmds, prettyCmds, false)
compileCFile(externalToCompile, script, cmds, prettyCmds, true)
if optCompileOnly notin gGlobalOptions:
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
if gNumberOfProcessors <= 1:
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
elif optListCmd in gGlobalOptions or gVerbosity > 0:
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
elif optListCmd in gGlobalOptions or gVerbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
gNumberOfProcessors)
else:
res = execProcesses(cmds, {poUseShell, poParentStreams},
elif gVerbosity == 1:
res = execProcesses(cmds, {poUseShell, poParentStreams},
gNumberOfProcessors, prettyCb)
else:
res = execProcesses(cmds, {poUseShell, poParentStreams},
gNumberOfProcessors)
if res != 0:
if gNumberOfProcessors <= 1:
@ -625,7 +652,6 @@ proc callCCompiler*(projectfile: string) =
if optGenStaticLib in gGlobalOptions:
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
"objfiles", objfiles]
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
else:
var linkerExe = getConfigVar(c, ".linkerexe")
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
@ -657,7 +683,11 @@ proc callCCompiler*(projectfile: string) =
"objfiles", objfiles, "exefile", exefile,
"nimrod", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
if optCompileOnly notin gGlobalOptions:
if gVerbosity == 1:
execExternalProgram(linkCmd, "[Linking]")
else:
execExternalProgram(linkCmd)
else:
linkCmd = ""
if optGenScript in gGlobalOptions:
@ -668,7 +698,7 @@ proc callCCompiler*(projectfile: string) =
proc genMappingFiles(list: TLinkedList): PRope =
var it = PStrEntry(list.head)
while it != nil:
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
it = PStrEntry(it.next)
proc writeMapping*(gSymbolMapping: PRope) =

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements Nimrod's standard template filter.
# This module implements Nim's standard template filter.
import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
@ -148,7 +148,7 @@ proc parseLine(p: var TTmplParser) =
inc(j)
else:
if p.x[j] == p.subsChar:
# parse Nimrod expression:
# parse Nim expression:
inc(j)
case p.x[j]
of '{':

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements Nimrod's simple filters and helpers for filters.
# This module implements Nim's simple filters and helpers for filters.
import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) =
fact.sons[2] = value
m.add fact
proc sameSubexprs*(m: TModel; a, b: PNode): bool =
# This should be used to check whether two *path expressions* refer to the
# same memory location according to 'm'. This is tricky:
# lock a[i].guard:
# ...
# access a[i].guarded
#
# Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'.
# However, nil checking requires exactly the same mechanism! But for now
# we simply use sameTree and live with the unsoundness of the analysis.
var check = newNodeI(nkCall, a.info, 3)
check.sons[0] = newSymNode(opEq)
check.sons[1] = a
check.sons[2] = b
result = m.doesImply(check) == impYes
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
let branch = n.sons[i]
if branch.kind == nkOfBranch:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -15,7 +15,7 @@ import
hashes, strutils
type
TIdObj* = object of TObject
TIdObj* = object of RootObj
id*: int # unique id; use this for comparisons and not the pointers
PIdObj* = ref TIdObj

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -53,7 +53,7 @@ proc saveMaxIds*(project: string) =
f.close()
proc loadMaxIds*(project: string) =
var f: TFile
var f: File
if open(f, project.toGid, fmRead):
var line = newStringOfCap(20)
if f.readLine(line):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -113,7 +113,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
e = nextIdentIter(it, fromMod.tab)
else: rawImportSymbol(c, s)
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
var i: TTabIter
var s = initTabIter(i, fromMod.tab)
while s != nil:
@ -126,10 +126,10 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
s = nextIter(i, fromMod.tab)
proc importAllSymbols*(c: PContext, fromMod: PSym) =
var exceptSet: TIntSet
var exceptSet: IntSet
importAllSymbolsExcept(c, fromMod, exceptSet)
proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
if n.isNil: return
case n.kind
of nkExportStmt:
@ -166,7 +166,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
proc evalImport(c: PContext, n: PNode): PNode =
result = n
var emptySet: TIntSet
var emptySet: IntSet
for i in countup(0, sonsLen(n) - 1):
var m = myImportModule(c, n.sons[i])
if m != nil:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -33,7 +33,7 @@ import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
intsets, cgmeth
intsets, cgmeth, lowerings
type
TTarget = enum
@ -71,8 +71,8 @@ type
TGlobals = object
typeInfo, code: PRope
forwarded: seq[PSym]
generatedSyms: TIntSet
typeInfoGenerated: TIntSet
generatedSyms: IntSet
typeInfoGenerated: IntSet
PGlobals = ref TGlobals
PProc = ref TProc
@ -113,7 +113,7 @@ proc rdLoc(a: TCompRes): PRope {.inline.} =
result = ropef("$1[$2]", a.address, a.res)
proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc =
options: TOptions): PProc =
result = PProc(
blocks: @[],
options: options,
@ -601,15 +601,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
if p.target == targetJS:
app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
if i < length and n.sons[i].kind == nkFinally:
gen(p, n.sons[i].sons[0], a)
moveInto(p, a, r)
genStmt(p, n.sons[i].sons[0])
if p.target == targetJS:
app(p.body, "}" & tnl)
if p.target == targetLua:
# we need to repeat the finally block for Lua ...
if i < length and n.sons[i].kind == nkFinally:
gen(p, n.sons[i].sons[0], a)
moveInto(p, a, r)
genStmt(p, n.sons[i].sons[0])
proc genRaiseStmt(p: PProc, n: PNode) =
genLineDir(p, n)
@ -724,7 +722,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
var sym = n.sons[0].sym
sym.loc.k = locOther
sym.loc.a = idx
sym.position = idx+1
setLen(p.blocks, idx + 1)
p.blocks[idx].id = - p.unique # negative because it isn't used yet
let labl = p.unique
@ -741,7 +739,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
assert(n.sons[0].kind == nkSym)
let sym = n.sons[0].sym
assert(sym.loc.k == locOther)
idx = sym.loc.a
idx = sym.position-1
else:
# an unnamed 'break' can only break a loop after 'transf' pass:
idx = len(p.blocks) - 1
@ -942,22 +940,21 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case s.kind
of skVar, skLet, skResult:
r.kind = resExpr
if mapType(n.typ) == etyObject:
if mapType(n.sons[0].typ) == etyObject:
# make addr() a no-op:
r.typ = etyNone
r.res = s.loc.r
r.address = nil
elif sfGlobal in s.flags:
# globals are always indirect accessible
r.typ = etyBaseIndex
r.address = toRope("Globals")
r.res = makeJSString(ropeToStr(s.loc.r))
elif sfAddrTaken in s.flags:
elif {sfGlobal, sfAddrTaken} * s.flags != {}:
# for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal.
r.typ = etyBaseIndex
r.address = s.loc.r
r.res = toRope("0")
else:
internalError(n.info, "genAddr: 4")
# 'var openArray' for instance produces an 'addr' but this is harmless:
gen(p, n.sons[0], r)
#internalError(n.info, "genAddr: 4 " & renderTree(n))
else: internalError(n.info, "genAddr: 2")
of nkCheckedFieldExpr:
genCheckedFieldAddr(p, n, r)
@ -981,7 +978,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
of skVar, skLet, skParam, skTemp, skResult:
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
var k = mapType(s.typ)
let k = mapType(s.typ)
if k == etyBaseIndex:
r.typ = etyBaseIndex
if {sfAddrTaken, sfGlobal} * s.flags != {}:
@ -990,7 +987,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else:
r.address = s.loc.r
r.res = con(s.loc.r, "_Idx")
elif k != etyObject and sfAddrTaken in s.flags:
elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
r.res = ropef("$1[0]", [s.loc.r])
else:
r.res = s.loc.r
@ -1078,8 +1075,16 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
useMagic(p, "rawEcho")
app(r.res, "rawEcho")
genArgs(p, n, r)
app(r.res, "rawEcho(")
let n = n[1].skipConv
internalAssert n.kind == nkBracket
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.typ.isCompileTimeOnly: continue
if i > 0: app(r.res, ", ")
genArg(p, it, r)
app(r.res, ")")
r.kind = resExpr
proc putToSeq(s: string, indirect: bool): PRope =
result = toRope(s)
@ -1162,8 +1167,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
internalError("createVar: " & $t.kind)
result = nil
proc isIndirect(v: PSym): bool =
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
proc isIndirect(v: PSym): bool =
result = {sfAddrTaken, sfGlobal} * v.flags != {} and
(mapType(v.typ) != etyObject) and
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
proc genVarInit(p: PProc, v: PSym, n: PNode) =
@ -1203,13 +1209,17 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
proc genVarStmt(p: PProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
assert(a.kind == nkIdentDefs)
assert(a.sons[0].kind == nkSym)
var v = a.sons[0].sym
if lfNoDecl in v.loc.flags: continue
genLineDir(p, a)
genVarInit(p, v, a.sons[2])
if a.kind != nkCommentStmt:
if a.kind == nkVarTuple:
let unpacked = lowerTupleUnpacking(a, p.prc)
genStmt(p, unpacked)
else:
assert(a.kind == nkIdentDefs)
assert(a.sons[0].kind == nkSym)
var v = a.sons[0].sym
if lfNoDecl notin v.loc.flags:
genLineDir(p, a)
genVarInit(p, v, a.sons[2])
proc genConstant(p: PProc, c: PSym) =
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
@ -1425,7 +1435,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
r.res = toRope("{")
r.kind = resExpr
for i in countup(1, sonsLen(n) - 1):
if i > 0: app(r.res, ", ")
if i > 1: app(r.res, ", ")
var it = n.sons[i]
internalAssert it.kind == nkExprColonExpr
gen(p, it.sons[1], a)
@ -1654,6 +1664,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = nil
of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r)
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals
@ -1664,11 +1675,11 @@ proc newModule(module: PSym): BModule =
if globals == nil: globals = newGlobals()
proc genHeader(): PRope =
result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
"/* (c) 2014 Andreas Rumpf */$n$n" &
"$nvar Globals = this;$n" &
"var framePtr = null;$n" &
"var excHandler = null;$n",
"var excHandler = null;$n" &
"var lastJSError = null;$n",
[toRope(VersionAsString)])
proc genModule(p: PProc, n: PNode) =

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -128,7 +128,7 @@ type
obj: PType
PEnv = ref TEnv
TEnv {.final.} = object of TObject
TEnv {.final.} = object of RootObj
attachedNode, replacementNode: PNode
createdVar: PNode # if != nil it is a used environment; for closure
# iterators this can be 'envParam.env'
@ -140,12 +140,12 @@ type
fn: PSym # function that belongs to this scope;
# if up.fn != fn then we cross function boundaries.
# This is an important case to consider.
vars: TIntSet # variables belonging to this environment
vars: IntSet # variables belonging to this environment
TOuterContext = object
fn: PSym # may also be a module!
head: PEnv
capturedVars, processed: TIntSet
capturedVars, processed: IntSet
localsToAccess: TIdNodeTable
lambdasToEnv: TIdTable # PSym->PEnv mapping

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -21,10 +21,10 @@ import
const
MaxLineLength* = 80 # lines longer than this lead to a warning
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
# don't forget to update the 'highlite' module if these charsets should change
@ -35,9 +35,10 @@ type
tkSymbol, # keywords:
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
tkBind, tkBlock, tkBreak, tkCase, tkCast,
tkConst, tkContinue, tkConverter, tkDiscard, tkDistinct, tkDiv, tkDo,
tkConst, tkContinue, tkConverter,
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
tkFinally, tkFor, tkFrom,
tkFinally, tkFor, tkFrom, tkFunc,
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
tkIs, tkIsnot, tkIterator,
tkLet,
@ -71,11 +72,12 @@ const
"tkSymbol",
"addr", "and", "as", "asm", "atomic",
"bind", "block", "break", "case", "cast",
"const", "continue", "converter", "discard", "distinct", "div", "do",
"const", "continue", "converter",
"defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "generic", "if",
"finally", "for", "from", "func", "generic", "if",
"import", "in", "include", "interface", "is", "isnot", "iterator",
"let",
"let",
"macro", "method", "mixin", "mod",
"nil", "not", "notin", "object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return",
@ -102,7 +104,7 @@ type
# so that it is the correct default value
base2, base8, base16
TToken* = object # a Nimrod token
TToken* = object # a Nim token
tokType*: TTokType # the type of the token
indent*: int # the indentation; != -1 if the token has been
# preceeded with indentation
@ -116,7 +118,8 @@ type
literal*: string # the parsed (string) literal; and
# documentation comments are here too
line*, col*: int
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
TLexer* = object of TBaseLexer
fileIdx*: int32
indentAhead*: int # if > 0 an indendation has already been read
@ -124,7 +127,7 @@ type
# needs so much look-ahead
currLineIndent*: int
strongSpaces*: bool
errorHandler*: TErrorHandler
var gLinesCompiled*: int # all lines that have been compiled
@ -148,7 +151,7 @@ proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
proc isKeyword(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isNimrodIdentifier*(s: string): bool =
proc isNimIdentifier*(s: string): bool =
if s[0] in SymStartChars:
var i = 1
while i < s.len:
@ -222,14 +225,20 @@ proc getColumn(L: TLexer): int =
proc getLineInfo(L: TLexer): TLineInfo =
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
msgs.message(getLineInfo(L), msg, arg)
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
if L.errorHandler.isNil:
msgs.message(info, msg, arg)
else:
L.errorHandler(info, msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
msgs.message(info, msg, arg)
L.dispMessage(info, msg, arg)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
var pos = L.bufpos # use registers for pos, buf
var buf = L.buf
while true:
@ -246,7 +255,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
inc(pos)
L.bufpos = pos
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
proc isFloatLiteral(s: string): bool =
@ -429,9 +438,9 @@ proc getNumber(L: var TLexer): TToken =
elif result.tokType == tkInt16Lit and
(result.iNumber < int16.low or result.iNumber > int16.high):
lexMessage(L, errNumberOutOfRange, result.literal)
except EInvalidValue:
except ValueError:
lexMessage(L, errInvalidNumber, result.literal)
except EOverflow, EOutOfRange:
except OverflowError, RangeError:
lexMessage(L, errNumberOutOfRange, result.literal)
L.bufpos = endpos
@ -482,7 +491,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
add(tok.literal, VT)
inc(L.bufpos)
of 't', 'T':
add(tok.literal, Tabulator)
add(tok.literal, '\t')
inc(L.bufpos)
of '\'', '\"':
add(tok.literal, L.buf[L.bufpos])
@ -519,7 +528,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
lexMessagePos(L, hintLineTooLong, pos)
if optEmbedOrigSrc in gGlobalOptions:
let lineStart = cast[TAddress](L.buf) + L.lineStart
let lineStart = cast[ByteAddress](L.buf) + L.lineStart
let line = newString(cast[cstring](lineStart), col)
addSourceLine(L.fileIdx, line)
@ -659,28 +668,32 @@ proc getOperator(L: var TLexer, tok: var TToken) =
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = -1
proc scanComment(L: var TLexer, tok: var TToken) =
proc scanComment(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
var buf = L.buf
# a comment ends if the next line does not start with the # on the same
# column after only whitespace
var buf = L.buf
when not defined(nimfix):
assert buf[pos+1] == '#'
if buf[pos+2] == '[':
lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
var col = getColNumber(L, pos)
when defined(nimfix):
var col = getColNumber(L, pos)
while true:
var lastBackslash = -1
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
if buf[pos] == '\\': lastBackslash = pos+1
add(tok.literal, buf[pos])
inc(pos)
if lastBackslash > 0:
# a backslash is a continuation character if only followed by spaces
# plus a newline:
while buf[lastBackslash] == ' ': inc(lastBackslash)
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
# false positive:
lastBackslash = -1
when defined(nimfix):
if lastBackslash > 0:
# a backslash is a continuation character if only followed by spaces
# plus a newline:
while buf[lastBackslash] == ' ': inc(lastBackslash)
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
# false positive:
lastBackslash = -1
pos = handleCRLF(L, pos)
buf = L.buf
@ -688,9 +701,16 @@ proc scanComment(L: var TLexer, tok: var TToken) =
while buf[pos] == ' ':
inc(pos)
inc(indent)
if buf[pos] == '#' and (col == indent or lastBackslash > 0):
when defined(nimfix):
template doContinue(): expr =
buf[pos] == '#' and (col == indent or lastBackslash > 0)
else:
template doContinue(): expr =
buf[pos] == '#' and buf[pos+1] == '#'
if doContinue():
tok.literal.add "\n"
col = indent
when defined(nimfix): col = indent
inc tok.iNumber
else:
if buf[pos] > ' ':
@ -707,7 +727,7 @@ proc skip(L: var TLexer, tok: var TToken) =
of ' ':
inc(pos)
inc(tok.strongSpaceA)
of Tabulator:
of '\t':
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
inc(pos)
of CR, LF:
@ -718,10 +738,24 @@ proc skip(L: var TLexer, tok: var TToken) =
inc(pos)
inc(indent)
tok.strongSpaceA = 0
if buf[pos] > ' ':
when defined(nimfix):
template doBreak(): expr = buf[pos] > ' '
else:
template doBreak(): expr =
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
if doBreak():
tok.indent = indent
L.currLineIndent = indent
break
of '#':
when defined(nimfix):
break
else:
# do not skip documentation comment:
if buf[pos+1] == '#': break
if buf[pos+1] == '[':
lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['")
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
else:
break # EndOfFile also leaves the loop
L.bufpos = pos

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,7 +12,7 @@
import os
type
PListEntry* = ref TListEntry
TListEntry* = object of TObject
TListEntry* = object of RootObj
prev*, next*: PListEntry
TStrEntry* = object of TListEntry

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -21,9 +21,9 @@ type
llsString, # stream encapsulates a string
llsFile, # stream encapsulates a file
llsStdIn # stream encapsulates stdin
TLLStream* = object of TObject
TLLStream* = object of RootObj
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
f*: TFile
f*: File
s*: string
rd*, wr*: int # for string streams
lineOffset*: int # for fake stdin line numbers
@ -31,8 +31,8 @@ type
PLLStream* = ref TLLStream
proc llStreamOpen*(data: string): PLLStream
proc llStreamOpen*(f: var TFile): PLLStream
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc llStreamOpen*(f: var File): PLLStream
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
proc llStreamOpen*(): PLLStream
proc llStreamOpenStdIn*(): PLLStream
proc llStreamClose*(s: PLLStream)
@ -50,12 +50,12 @@ proc llStreamOpen(data: string): PLLStream =
result.s = data
result.kind = llsString
proc llStreamOpen(f: var TFile): PLLStream =
proc llStreamOpen(f: var File): PLLStream =
new(result)
result.f = f
result.kind = llsFile
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
proc llStreamOpen(filename: string, mode: FileMode): PLLStream =
new(result)
result.kind = llsFile
if not open(result.f, filename, mode): result = nil

View file

@ -114,7 +114,7 @@ type
mode*: TOverloadIterMode
symChoiceIndex*: int
scope*: PScope
inSymChoice: TIntSet
inSymChoice: IntSet
proc getSymRepr*(s: PSym): string =
case s.kind

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -51,13 +51,14 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, value.info)
v.addVar(newSymNode(temp))
let tempAsNode = newSymNode(temp)
v.addVar(tempAsNode)
result.add(v)
result.add newAsgnStmt(newSymNode(temp), value)
result.add newAsgnStmt(tempAsNode, value)
for i in 0 .. n.len-3:
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
proc createObj*(owner: PSym, info: TLineInfo): PType =
result = newType(tyObject, owner)
@ -204,7 +205,7 @@ proc flowVarKind(t: PType): TFlowVarKind =
else: fvBlob
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
v: PNode): PSym =
v: PNode; useShallowCopy=false): PSym =
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
result.typ = typ
incl(result.flags, sfFromGeneric)
@ -215,11 +216,14 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
varSection.add vpart
if varInit != nil:
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
deepCopyCall.sons[1] = newSymNode(result)
deepCopyCall.sons[2] = v
varInit.add deepCopyCall
if useShallowCopy:
varInit.add newFastAsgnStmt(newSymNode(result), v)
else:
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
deepCopyCall.sons[1] = newSymNode(result)
deepCopyCall.sons[2] = v
varInit.add deepCopyCall
discard """
We generate roughly this:
@ -261,7 +265,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
barrier.typ, barrier)
body.add varSection2
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
var threadLocalProm: PSym
if spawnKind == srByVar:
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
@ -276,7 +280,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
"owner", fv.info), threadParam.newSymNode)
body.add callCodeGenProc("nimArgsPassingDone", threadParam.newSymNode)
body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
if spawnKind == srByVar:
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
elif fv != nil:
@ -286,14 +290,20 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
typeToString(fv.typ.sons[1]))
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
if fk == fvGC: "data" else: "blob", fv.info), call)
if fk == fvGC:
let incRefCall = newNodeI(nkCall, fv.info, 2)
incRefCall.sons[0] = newSymNode(createMagic("GCref", mGCref))
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
"data", fv.info)
body.add incRefCall
if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need
# to use the thread-local view instead:
body.add callCodeGenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
else:
body.add call
if barrier != nil:
body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode)
body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode
@ -414,7 +424,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
indirectAccess(castExpr, fieldA, n.info))
indirectAccess(castExpr, fieldA, n.info),
useShallowCopy=true)
slice.sons[2] = threadLocal.newSymNode
else:
let a = genAddrOf(n)
@ -428,7 +439,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
indirectAccess(castExpr, fieldB, n.info))
indirectAccess(castExpr, fieldB, n.info),
useShallowCopy=true)
slice.sons[3] = threadLocal.newSymNode
call.add slice
elif (let size = computeSize(argType); size < 0 or size > 16) and
@ -439,7 +451,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info))
indirectAccess(castExpr, field, n.info),
useShallowCopy=true)
call.add(genDeref(threadLocal.newSymNode))
else:
# boring case
@ -448,7 +461,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
let threadLocal = addLocalVar(varSection, varInit,
objType.owner, field.typ,
indirectAccess(castExpr, field, n.info))
indirectAccess(castExpr, field, n.info),
useShallowCopy=true)
call.add(threadLocal.newSymNode)
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
@ -543,7 +557,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
# create flowVar:
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
if barrier == nil:
result.add callCodeGenProc("nimFlowVarCreateCondVar", fvField)
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
elif spawnKind == srByVar:
var field = newSym(skField, getIdent"fv", owner, n.info)
@ -556,7 +570,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
let wrapper = createWrapperProc(fn, threadParam, argsParam,
varSection, varInit, call,
barrierAsExpr, fvAsExpr, spawnKind)
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
genAddrOf(scratchObj.newSymNode))
if spawnKind == srFlowVar: result.add fvField

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -35,7 +35,7 @@ proc registerSysType(t: PType) =
proc newSysType(kind: TTypeKind, size: int): PType =
result = newType(kind, systemModule)
result.size = size
result.align = size
result.align = size.int16
proc getSysSym(name: string): PSym =
result = strTableGet(systemModule.tab, getIdent(name))
@ -44,6 +44,7 @@ proc getSysSym(name: string): PSym =
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter
@ -165,13 +166,14 @@ proc setIntLitType*(result: PNode) =
proc getCompilerProc(name: string): PSym =
var ident = getIdent(name, hashIgnoreStyle(name))
result = strTableGet(compilerprocs, ident)
if result == nil:
if result == nil:
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)
proc registerCompilerProc(s: PSym) =
if result.kind == skAlias: result = result.owner
proc registerCompilerProc(s: PSym) =
strTableAdd(compilerprocs, s)
proc finishSystem(tab: TStrTable) = discard

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -15,8 +15,7 @@ import
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
pretty
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
from magicsys import systemModule, resetSysTypes
@ -164,19 +163,6 @@ proc commandEval(exp: string) =
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(echoExp.parseString, makeStdinModule())
proc commandPrettyOld =
var projectFile = addFileExt(mainCommandArg(), NimExt)
var module = parseFile(projectFile.fileInfoIdx)
if module != nil:
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
proc commandPretty =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
registerPass(prettyPass)
compileProject()
pretty.overwriteFiles()
proc commandScan =
var f = addFileExt(mainCommandArg(), NimExt)
var stream = llStreamOpen(f, fmRead)
@ -217,25 +203,6 @@ proc commandSuggest =
else: gProjectMainIdx
compileProject(projFile)
proc wantMainModule =
if gProjectFull.len == 0:
if optMainModule.len == 0:
fatal(gCmdLineInfo, errCommandExpectsFilename)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc requireMainModuleOption =
if optMainModule.len == 0:
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc resetMemory =
resetCompilationLists()
ccgutils.resetCaches()
@ -299,30 +266,22 @@ proc mainCommand* =
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setId(100)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
case command.normalize
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
gCmd = cmdCompileToC
wantMainModule()
commandCompileToC()
of "cpp", "compiletocpp":
extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gcc")
wantMainModule()
defineSymbol("cpp")
commandCompileToC()
of "objc", "compiletooc":
extccomp.cExt = ".m"
gCmd = cmdCompileToOC
wantMainModule()
defineSymbol("objc")
commandCompileToC()
of "run":
gCmd = cmdRun
wantMainModule()
when hasTinyCBackend:
extccomp.setCC("tcc")
commandCompileToC()
@ -330,41 +289,33 @@ proc mainCommand* =
rawMessage(errInvalidCommandX, command)
of "js", "compiletojs":
gCmd = cmdCompileToJS
wantMainModule()
commandCompileToJS()
of "compiletollvm":
gCmd = cmdCompileToLLVM
wantMainModule()
when hasLLVM_Backend:
CommandCompileToLLVM()
else:
rawMessage(errInvalidCommandX, command)
of "pretty":
gCmd = cmdPretty
wantMainModule()
commandPretty()
of "doc":
wantMainModule()
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
commandDoc()
of "doc2":
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
defineSymbol("nimdoc")
commandDoc2()
of "rst2html":
gCmd = cmdRst2html
loadConfigs(DocConfig)
wantMainModule()
commandRst2Html()
of "rst2tex":
gCmd = cmdRst2tex
loadConfigs(DocTexConfig)
wantMainModule()
commandRst2TeX()
of "jsondoc":
wantMainModule()
gCmd = cmdDoc
loadConfigs(DocConfig)
wantMainModule()
@ -376,12 +327,11 @@ proc mainCommand* =
commandBuildIndex()
of "gendepend":
gCmd = cmdGenDepend
wantMainModule()
commandGenDepend()
of "dump":
gCmd = cmdDump
if getConfigVar("dump.format") == "json":
requireMainModuleOption()
wantMainModule()
var definedSymbols = newJArray()
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
@ -405,7 +355,6 @@ proc mainCommand* =
for it in iterSearchPath(searchPaths): msgWriteln(it)
of "check":
gCmd = cmdCheck
wantMainModule()
commandCheck()
of "parse":
gCmd = cmdParse
@ -429,7 +378,6 @@ proc mainCommand* =
if gEvalExpr != "":
commandEval(gEvalExpr)
else:
wantMainModule()
commandSuggest()
of "serve":
isServing = true

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -117,7 +117,7 @@ proc newModule(fileIdx: int32): PSym =
result.kind = skModule
let filename = fileIdx.toFullPath
result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
if not isNimIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
result.info = newLineInfo(fileIdx, 1, 1)
@ -177,7 +177,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
proc `==^`(a, b: string): bool =
try:
result = sameFile(a, b)
except EOS:
except OSError:
result = false
proc compileSystemModule* =
@ -185,8 +185,18 @@ proc compileSystemModule* =
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard compileModule(systemFileIdx, {sfSystemModule})
proc compileProject*(projectFile = gProjectMainIdx) =
proc wantMainModule* =
if gProjectFull.len == 0:
fatal(gCmdLineInfo, errCommandExpectsFilename)
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
proc compileProject*(projectFileIdx = -1'i32) =
wantMainModule()
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
if projectFile == systemFileIdx:
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
else:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -114,17 +114,18 @@ type
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnNilStatement, warnAnalysisLoophole,
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnUser,
warnUninit, warnGcMem, warnLockLevel, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintPattern,
hintConditionAlwaysTrue, hintName, hintPattern,
hintUser
const
@ -368,13 +369,14 @@ const
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
warnDeprecated: "\'$1\' is deprecated [Deprecated]",
warnDeprecated: "$1 is deprecated [Deprecated]",
warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
@ -387,9 +389,10 @@ const
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnLockLevel: "$1 [LockLevel]",
warnUser: "$1 [User]",
hintSuccess: "operation successful [Success]",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
@ -405,25 +408,27 @@ const
hintConf: "used config file \'$1\' [Conf]",
hintPath: "added path: '$1' [Path]",
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
hintName: "name should be: '$1' [Name]",
hintPattern: "$1 [Pattern]",
hintUser: "$1 [User]"]
const
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
WarningsToStr*: array[0..28, string] = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "User"]
"GcMem", "LockLevel", "User"]
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "Pattern",
"Path", "CondTrue", "Name", "Pattern",
"User"]
const
@ -441,11 +446,11 @@ type
TNoteKinds* = set[TNoteKind]
TFileInfo*{.final.} = object
fullPath*: string # This is a canonical full filesystem path
fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
shortName*: string # short name of the module
quotedName*: PRope # cached quoted short name for codegen
# purpoes
# purposes
lines*: seq[PRope] # the source code of the module
# used for better error messages and
@ -468,8 +473,8 @@ type
TErrorOutputs* = set[TErrorOutput]
ERecoverableError* = object of EInvalidValue
ESuggestDone* = object of E_Base
ERecoverableError* = object of ValueError
ESuggestDone* = object of Exception
const
InvalidFileIDX* = int32(-1)
@ -567,7 +572,7 @@ var
gErrorMax*: int = 1 # stop after gErrorMax errors
when useCaas:
var stdoutSocket*: TSocket
var stdoutSocket*: Socket
proc unknownLineInfo*(): TLineInfo =
result.line = int16(-1)
@ -784,6 +789,14 @@ proc writeSurroundingSrc(info: TLineInfo) =
msgWriteln(indent & info.sourceLine.ropeToStr)
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
let frmt = case msg
of warnMin..warnMax: PosWarningFormat
of hintMin..hintMax: PosHintFormat
else: PosErrorFormat
result = frmt % [toMsgFilename(info), coordToStr(info.line),
coordToStr(info.col), getMessageStr(msg, arg)]
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
var frmt: string
@ -858,7 +871,7 @@ proc sourceLine*(i: TLineInfo): PRope =
try:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
except EIO:
except IOError:
discard
internalAssert i.fileIndex < fileInfos.len
# can happen if the error points to EOF:

View file

@ -2,7 +2,7 @@
; and project.
[Project]
Name: "Nimrod"
Name: "Nim"
Version: "$version"
Platforms: """
windows: i386;amd64
@ -16,15 +16,15 @@ Platforms: """
"""
Authors: "Andreas Rumpf"
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
Description: """This is the Nim Compiler. Nim is a new statically typed,
imperative programming language, that supports procedural, functional, object
oriented and generic programming styles while remaining simple and efficient.
A special feature that Nimrod inherited from Lisp is that Nimrod's abstract
A special feature that Nim inherited from Lisp is that Nim's abstract
syntax tree (AST) is part of the specification - this allows a powerful macro
system which can be used to create domain specific languages.
Nimrod is a compiled, garbage-collected systems programming language
which has an excellent productivity/performance ratio. Nimrod's design
Nim is a compiled, garbage-collected systems programming language
which has an excellent productivity/performance ratio. Nim's design
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
priority)."""
@ -32,7 +32,7 @@ App: Console
License: "copying.txt"
[Config]
Files: "config/nimrod.cfg"
Files: "config/nim.cfg"
Files: "config/nimdoc.cfg"
Files: "config/nimdoc.tex.cfg"
@ -61,8 +61,8 @@ Files: "icons/koch.res"
Files: "icons/koch_icon.o"
Files: "compiler/readme.txt"
Files: "compiler/nimrod.ini"
Files: "compiler/nimrod.cfg"
Files: "compiler/nim.ini"
Files: "compiler/nim.nimrod.cfg"
Files: "compiler/*.nim"
Files: "doc/*.txt"
Files: "compiler/nimfix/*.nim"
@ -113,10 +113,9 @@ Files: "examples/*.tmpl"
[Windows]
Files: "bin/nimrod.exe"
Files: "bin/nimrod_debug.exe"
Files: "bin/nim.exe"
Files: "bin/nim_debug.exe"
Files: "bin/c2nim.exe"
Files: "bin/niminst.exe"
Files: "bin/nimgrep.exe"
Files: "dist/*.dll"
@ -132,7 +131,7 @@ Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia
; for now only NSIS supports optional downloads
[UnixBin]
Files: "bin/nimrod"
Files: "bin/nim"
[Unix]
@ -156,6 +155,5 @@ flags = "-w"
[deb]
buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nimrod Compiler"
licenses: "bin/nimrod,MIT;lib/*,MIT;"
shortDesc: "The Nim Compiler"
licenses: "bin/nim,MIT;lib/*,MIT;"

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -40,7 +40,7 @@ proc handleCmdLine() =
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
except EOS:
except OSError:
gProjectFull = gProjectName
var p = splitFile(gProjectFull)
gProjectPath = p.dir
@ -58,7 +58,7 @@ proc handleCmdLine() =
if msgs.gErrorCounter == 0:
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.run(service.arguments)
tccgen.run(commands.arguments)
if optRun in gGlobalOptions:
if gCmd == cmdCompileToJS:
var ex: string
@ -67,7 +67,7 @@ proc handleCmdLine() =
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & service.arguments)
execExternalProgram("node " & ex & ' ' & commands.arguments)
else:
var binPath: string
if options.outFile.len > 0:
@ -77,7 +77,7 @@ proc handleCmdLine() =
# Figure out ourselves a valid binary name.
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(ex & ' ' & service.arguments)
execExternalProgram(ex & ' ' & commands.arguments)
when declared(GC_setMaxPause):
GC_setMaxPause 2_000

View file

@ -1,6 +1,4 @@
# Special configuration file for the Nimrod project
mainModule:"nimrod.nim"
# Special configuration file for the Nim project
# gc:markAndSweep
@ -21,3 +19,4 @@ define:useStdoutAsStdmsg
cs:partial
#define:useNodeIds
symbol:nimfix

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements some helper procs for Babel (Nimrod's package manager) support.
## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, strtabs, os, options, msgs, lists
@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool =
if a[i] == '.': inc i
if b[j] == '.': inc j
proc addPackage(packages: PStringTable, p: string) =
proc addPackage(packages: StringTableRef, p: string) =
let x = versionSplitPos(p)
let name = p.substr(0, x-1)
if x < p.len:
@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) =
else:
packages[name] = latest
iterator chosen(packages: PStringTable): string =
iterator chosen(packages: StringTableRef): string =
for key, val in pairs(packages):
let res = if val == latest: key else: key & '-' & val
yield res
proc addBabelPath(p: string, info: TLineInfo) =
proc addNimblePath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p):
if gVerbosity >= 1: message(info, hintPath, p)
lists.prependStr(options.lazyPaths, p)
@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) =
result = true
break
if hasNimFile(p):
addBabelPath(p, info)
addNimblePath(p, info)
else:
for kind, p2 in walkDir(p):
if hasNimFile(p2): addBabelPath(p2, info)
if hasNimFile(p2): addNimblePath(p2, info)
proc addPathRec(dir: string, info: TLineInfo) =
var packages = newStringTable(modeStyleInsensitive)
@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) =
if k == pcDir and p[pos] != '.':
addPackage(packages, p)
for p in packages.chosen:
addBabelPath(p, info)
addNimblePath(p, info)
proc babelPath*(path: string, info: TLineInfo) =
proc nimblePath*(path: string, info: TLineInfo) =
addPathRec(path, info)
addBabelPath(path, info)
addNimblePath(path, info)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -14,7 +14,7 @@ import
options, idents, wordrecg
# ---------------- configuration file parser -----------------------------
# we use Nimrod's scanner here to safe space and work
# we use Nim's scanner here to safe space and work
proc ppGetTok(L: var TLexer, tok: var TToken) =
# simple filter
@ -113,7 +113,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
case whichKeyword(tok.ident)
of wIf:
setLen(condStack, len(condStack) + 1)
var res = evalppIf(L, tok)
let res = evalppIf(L, tok)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok)
@ -224,8 +224,10 @@ proc loadConfigs*(cfg: string) =
if libpath == "":
# choose default libpath:
var prefix = getPrefixDir()
if prefix == "/usr": libpath = "/usr/lib/nimrod"
elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod"
when defined(posix):
if prefix == "/usr": libpath = "/usr/lib/nim"
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
else: libpath = joinPath(prefix, "lib")
else: libpath = joinPath(prefix, "lib")
if optSkipConfigFile notin gGlobalOptions:
@ -244,5 +246,6 @@ proc loadConfigs*(cfg: string) =
if gProjectName.len != 0:
# new project wide config file:
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
let projectConfig = changeFileExt(gProjectFull, "nim.cfg")
if fileExists(projectConfig): readConfigFile(projectConfig)
else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## exposes the Nimrod VM to clients.
## exposes the Nim VM to clients.
import
ast, modules, passes, passaux, condsyms,

View file

@ -16,7 +16,7 @@ import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
const Usage = """
Nimfix - Tool to patch Nim code
Usage:
nimfix [options] projectflie.nim
nimfix [options] projectfile.nim
Options:
--overwriteFiles:on|off overwrite the original nim files.
@ -26,12 +26,13 @@ Options:
--styleCheck:on|off|auto performs style checking for identifiers
and suggests an alternative spelling;
'auto' corrects the spelling.
--bestEffort try to fix the code even when there
are errors.
In addition, all command line options of Nim are supported.
"""
proc mainCommand =
#msgs.gErrorMax = high(int) # do not stop after first error
registerPass verbosePass
registerPass semPass
gCmd = cmdPretty
@ -63,13 +64,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
of "on": gCheckExtern = true
of "off": gCheckExtern = false
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "stylecheck":
of "stylecheck":
case p.val.normalize
of "off": gStyleCheck = StyleCheck.None
of "on": gStyleCheck = StyleCheck.Warn
of "auto": gStyleCheck = StyleCheck.Auto
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "wholeproject": gOnlyMainfile = false
of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error
else:
processSwitch(pass, p)
of cmdArgument:

View file

@ -34,7 +34,7 @@ proc loadFile*(info: TLineInfo) =
for line in lines(path):
gSourceFiles[i].lines.add(line)
# extract line ending of the file:
var lex: TBaseLexer
var lex: BaseLexer
open(lex, newFileStream(path, fmRead))
var pos = lex.bufpos
while true:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -37,7 +37,7 @@ const
NewLines* = {CR, LF}
type
TBaseLexer* = object of TObject
TBaseLexer* = object of RootObj
bufpos*: int
buf*: cstring
bufLen*: int # length of buffer in characters

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# this unit handles Nimrod sets; it implements symbolic sets
# this unit handles Nim sets; it implements symbolic sets
import
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer

View file

@ -1,21 +1,17 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module contains Nimrod's version. It is the only place where it needs
# This module contains Nim's version. It is the only place where it needs
# to be changed.
const
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
VersionMajor* = 0
VersionMinor* = 9
VersionPatch* = 7
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
VersionAsString* = system.NimVersion
RodFileVersion* = "1215" # modify this if the rod-format changes!

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -68,7 +68,7 @@ type # please make sure we have under 32 options
# also: generate header file
TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands
TCommands* = enum # Nim's commands
# **keep binary compatible**
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
@ -114,7 +114,8 @@ var
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
# the tracked source X, saved by the CAAS client.
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
gNoBabelPath* = false
gNoNimblePath* = false
gExperimentalMode*: bool
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
@ -139,7 +140,7 @@ const
JsonExt* = "json"
TexExt* = "tex"
IniExt* = "ini"
DefaultConfig* = "nimrod.cfg"
DefaultConfig* = "nim.cfg"
DocConfig* = "nimdoc.cfg"
DocTexConfig* = "nimdoc.tex.cfg"
@ -152,7 +153,6 @@ var
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
gProjectFull* = "" # projectPath/projectName
gProjectMainIdx*: int32 # the canonical path id of the main module
optMainModule* = "" # the main module that should be used for idetools commands
nimcacheDir* = ""
command* = "" # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] = @[] # any arguments after the main command
@ -189,8 +189,8 @@ proc getPrefixDir*(): string =
result = splitPath(getAppDir()).head
proc canonicalizePath*(path: string): string =
result = path.expandFilename
when not FileSystemCaseSensitive: result = result.toLower
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
else: result = path.expandFilename
proc shortenDir*(dir: string): string =
## returns the interesting part of a dir
@ -238,6 +238,9 @@ proc getPackageName*(path: string): string =
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name
break packageSearch
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
@ -295,7 +298,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
createDir(subdir)
when noTimeMachine:
excludeDirFromTimeMachine(subdir)
except EOS:
except OSError:
writeln(stdout, "cannot create directory: " & subdir)
quit(1)
result = joinPath(subdir, tail)
@ -335,6 +338,16 @@ proc findFile*(f: string): string {.procvar.} =
proc findModule*(modulename, currentModule: string): string =
# returns path to module
when defined(nimfix):
# '.nimfix' modules are preferred over '.nim' modules so that specialized
# versions can be kept for 'nimfix'.
block:
let m = addFileExt(modulename, "nimfix")
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(m)
if existsFile(result): return result
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements the parser of the standard Nimrod syntax.
# This module implements the parser of the standard Nim syntax.
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
# it uses several helper routines to keep the parser small. A special
# efficient algorithm is used for the precedence levels. The parser here can
@ -41,8 +41,7 @@ type
proc parseAll*(p: var TParser): PNode
proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode
proc parseString*(s: string, filename: string = "", line: int = 0): PNode
# helpers for the other parsers
proc isOperator*(tok: TToken): bool
proc getTok*(p: var TParser)
@ -84,7 +83,7 @@ proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
strongSpaces=false) =
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
openParser(p, filename.fileInfoIdx, inputStream, strongSpaces)
proc closeParser(p: var TParser) =
## Close a parser, freeing up its resources.
@ -96,7 +95,7 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
## Produce and emit a parser message to output about the token `tok`
lexMessage(p.lex, msg, prettyTok(tok))
parMessage(p, msg, prettyTok(tok))
template withInd(p: expr, body: stmt) {.immediate.} =
let oldInd = p.currInd
@ -189,18 +188,13 @@ proc parseTypeDesc(p: var TParser): PNode
proc parseDoBlocks(p: var TParser, call: PNode)
proc parseParamList(p: var TParser, retColon = true): PNode
proc relevantOprChar(ident: PIdent): char {.inline.} =
result = ident.s[0]
var L = ident.s.len
if result == '\\' and L > 1:
result = ident.s[1]
proc isSigilLike(tok: TToken): bool {.inline.} =
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
proc isLeftAssociative(tok: TToken): bool {.inline.} =
## Determines whether the token is left assocative.
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
proc isRightAssociative(tok: TToken): bool {.inline.} =
## Determines whether the token is right assocative.
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token.
@ -210,7 +204,10 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
case tok.tokType
of tkOpr:
let L = tok.ident.s.len
let relevantChar = relevantOprChar(tok.ident)
let relevantChar = tok.ident.s[0]
# arrow like?
if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
@ -270,17 +267,18 @@ proc checkBinary(p: TParser) {.inline.} =
#|
#| optInd = COMMENT?
#| optPar = (IND{>} | IND{=})?
#|
#| simpleExpr = assignExpr (OP0 optInd assignExpr)*
#| assignExpr = orExpr (OP1 optInd orExpr)*
#| orExpr = andExpr (OP2 optInd andExpr)*
#| andExpr = cmpExpr (OP3 optInd cmpExpr)*
#| cmpExpr = sliceExpr (OP4 optInd sliceExpr)*
#| sliceExpr = ampExpr (OP5 optInd ampExpr)*
#| ampExpr = plusExpr (OP6 optInd plusExpr)*
#| plusExpr = mulExpr (OP7 optInd mulExpr)*
#| mulExpr = dollarExpr (OP8 optInd dollarExpr)*
#| dollarExpr = primary (OP9 optInd primary)*
#|
#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
#| assignExpr = orExpr (OP2 optInd orExpr)*
#| orExpr = andExpr (OP3 optInd andExpr)*
#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
#| ampExpr = plusExpr (OP7 optInd plusExpr)*
#| plusExpr = mulExpr (OP8 optInd mulExpr)*
#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
#| dollarExpr = primary (OP10 optInd primary)*
proc colcom(p: var TParser, n: PNode) =
eat(p, tkColon)
@ -507,7 +505,7 @@ proc parsePar(p: var TParser): PNode =
getTok(p)
optInd(p, result)
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
tkTry, tkFinally, tkExcept, tkFor, tkBlock,
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
tkConst, tkLet, tkWhen, tkVar,
tkMixin}:
# XXX 'bind' used to be an expression, so we exclude it here;
@ -735,7 +733,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
# the operator itself must not start on a new line:
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
checkBinary(p)
var leftAssoc = ord(isLeftAssociative(p.tok))
var leftAssoc = 1-ord(isRightAssociative(p.tok))
var a = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
getTok(p)
@ -896,7 +894,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
var a: PNode
result = newNodeP(nkFormalParams, p)
addSon(result, ast.emptyNode) # return type
if p.tok.tokType == tkParLe and p.tok.indent < 0:
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
if hasParLe:
getTok(p)
optInd(p, result)
while true:
@ -920,6 +919,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
getTok(p)
optInd(p, result)
result.sons[0] = parseTypeDesc(p)
elif not retColon and not hasParle:
# Mark as "not there" in order to mark for deprecation in the semantic pass:
result = ast.emptyNode
proc optPragmas(p: var TParser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
@ -1132,7 +1134,7 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
addSon(result, makeStmtList(body))
while sameInd(p):
var b: PNode
case p.tok.tokType
@ -1424,9 +1426,10 @@ proc parseBlock(p: var TParser): PNode =
colcom(p, result)
addSon(result, parseStmt(p))
proc parseStatic(p: var TParser): PNode =
proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
#| staticStmt = 'static' colcom stmt
result = newNodeP(nkStaticStmt, p)
#| deferStmt = 'defer' colcom stmt
result = newNodeP(k, p)
getTokNoInd(p)
colcom(p, result)
addSon(result, parseStmt(p))
@ -1864,7 +1867,7 @@ proc simpleStmt(p: var TParser): PNode =
proc complexOrSimpleStmt(p: var TParser): PNode =
#| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
#| | tryStmt | finallyStmt | exceptStmt | forStmt
#| | blockStmt | staticStmt | asmStmt
#| | blockStmt | staticStmt | deferStmt | asmStmt
#| | 'proc' routine
#| | 'method' routine
#| | 'iterator' routine
@ -1885,7 +1888,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
of tkFor: result = parseFor(p)
of tkBlock: result = parseBlock(p)
of tkStatic: result = parseStatic(p)
of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
of tkDefer: result = parseStaticOrDefer(p, nkDefer)
of tkAsm: result = parseAsm(p)
of tkProc: result = parseRoutine(p, nkProcDef)
of tkMethod: result = parseRoutine(p, nkMethodDef)
@ -1980,22 +1984,25 @@ proc parseTopLevelStmt(p: var TParser): PNode =
## top-level statement or emptyNode if end of stream.
result = ast.emptyNode
while true:
if p.tok.indent != 0:
if p.tok.indent != 0:
if p.firstTok and p.tok.indent < 0: discard
else: parMessage(p, errInvalidIndentation)
elif p.tok.tokType != tkSemiColon:
parMessage(p, errInvalidIndentation)
p.firstTok = false
case p.tok.tokType
of tkSemiColon:
getTok(p)
if p.tok.indent <= 0: discard
else: parMessage(p, errInvalidIndentation)
p.firstTok = true
of tkEof: break
else:
result = complexOrSimpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
break
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
proc parseString*(s: string; filename: string = ""; line: int = 0;
errorHandler: TErrorHandler = nil): PNode =
## Parses a string into an AST, returning the top node.
## `filename` and `line`, although optional, provide info so that the
## compiler can generate correct error messages referring to the original
@ -2007,6 +2014,7 @@ proc parseString(s: string, filename: string = "", line: int = 0): PNode =
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces...
openParser(parser, filename, stream, false)
parser.lex.errorHandler = errorHandler
result = parser.parseAll
closeParser(parser)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -16,7 +16,7 @@ import
nimsets, syntaxes, times, rodread, idgen
type
TPassContext* = object of TObject # the pass's context
TPassContext* = object of RootObj # the pass's context
fromCache*: bool # true if created by "openCached"
PPassContext* = ref TPassContext

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -260,7 +260,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
# couldn't bind parameter:
if isNil(x): return nil
result.add(x)
if requiresAA: addToArgList(args, n)
if requiresAA: addToArgList(args, x)
# perform alias analysis here:
if requiresAA:
for i in 1 .. < params.len:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -45,7 +45,7 @@ const
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt, wDeprecated}
wInjectStmt, wDeprecated, wExperimental}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
@ -71,7 +71,7 @@ const
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation
proc invalidPragma(n: PNode) =
proc invalidPragma(n: PNode) =
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
proc pragmaAsm*(c: PContext, n: PNode): char =
@ -130,6 +130,7 @@ proc processImportCpp(s: PSym, extname: string) =
excl(s.flags, sfForward)
let m = s.getModule()
incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true
proc processImportObjC(s: PSym, extname: string) =
setExternName(s, extname)
@ -356,11 +357,11 @@ proc processPush(c: PContext, n: PNode, start: int) =
append(c.optionStack, x)
for i in countup(start, sonsLen(n) - 1):
if processOption(c, n.sons[i]):
# simply store it somehwere:
# simply store it somewhere:
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n.sons[i]
#LocalError(n.info, errOptionExpected)
#localError(n.info, errOptionExpected)
proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1:
@ -447,6 +448,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
addSon(result, newSymNode(e))
else:
addSon(result, newStrNode(nkStrLit, sub))
else:
# an empty '``' produces a single '`'
addSon(result, newStrNode(nkStrLit, $marker))
if c < 0: break
a = c + 1
else: illFormedAst(n)
@ -518,6 +522,28 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
else:
invalidPragma(n)
proc pragmaLockStmt(c: PContext; it: PNode) =
if it.kind != nkExprColonExpr:
invalidPragma(it)
else:
let n = it[1]
if n.kind != nkBracket:
localError(n.info, errGenerated, "locks pragma takes a list of expressions")
else:
for i in 0 .. <n.len:
n.sons[i] = c.semExpr(c, n.sons[i])
proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
if it.kind != nkExprColonExpr:
invalidPragma(it)
else:
if it[1].kind != nkNilLit:
let x = expectIntLit(c, it)
if x < 0 or x > MaxLockLevel:
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
else:
result = TLockLevel(x)
proc typeBorrow(sym: PSym, n: PNode) =
if n.kind == nkExprColonExpr:
let it = n.sons[1]
@ -575,6 +601,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas)
# ensure the pragma is also remember for generic instantiations in other
# modules:
n.sons[i] = userPragma.ast
dec c.instCounter
else:
var k = whichKeyword(key.ident)
@ -807,6 +836,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym == nil: invalidPragma(it)
of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wLocks:
if sym == nil: pragmaLockStmt(c, it)
elif sym.typ == nil: invalidPragma(it)
else: sym.typ.lockLevel = pragmaLocks(c, it)
of wGuard:
if sym == nil or sym.kind notin {skVar, skLet, skField}:
invalidPragma(it)
@ -817,6 +850,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
of wExperimental:
noVal(it)
if isTopLevel(c):
c.module.flags.incl sfExperimental
else:
localError(it.info, "'experimental' pragma only valid as toplevel statement")
else: invalidPragma(it)
else: invalidPragma(it)
else: processNote(c, it)
@ -853,8 +892,13 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
return false
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return
for i in countup(0, sonsLen(n) - 1):
if singlePragma(c, sym, n, i, validPragmas): break
if n.sons[i].kind == nkPragma: pragmaRec(c, sym, n.sons[i], validPragmas)
elif singlePragma(c, sym, n, i, validPragmas): break
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return
pragmaRec(c, sym, n, validPragmas)
implicitPragmas(c, sym, n, validPragmas)

View file

@ -1,281 +0,0 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the code "prettifier". This is part of the toolchain
## to convert Nimrod code into a consistent style.
import
strutils, os, options, ast, astalgo, msgs, ropes, idents, passes,
intsets, strtabs, semdata
const
removeTP = false # when true, "nimrod pretty" converts TTyp to Typ.
type
TGen = object of TPassContext
module*: PSym
PGen = ref TGen
TSourceFile = object
lines: seq[string]
dirty: bool
fullpath: string
var
gSourceFiles: seq[TSourceFile] = @[]
gCheckExtern: bool
rules: PStringTable
proc loadFile(info: TLineInfo) =
let i = info.fileIndex
if i >= gSourceFiles.len:
gSourceFiles.setLen(i+1)
if gSourceFiles[i].lines.isNil:
gSourceFiles[i].lines = @[]
let path = info.toFullPath
gSourceFiles[i].fullpath = path
# we want to die here for EIO:
for line in lines(path):
gSourceFiles[i].lines.add(line)
proc overwriteFiles*() =
let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on"
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles):
if not gSourceFiles[i].dirty: continue
let newFile = if overWrite: gSourceFiles[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
try:
var f = open(newFile, fmWrite)
for line in gSourceFiles[i].lines:
if doStrip:
f.write line.strip(leading = false, trailing = true)
else:
f.write line
f.write("\L")
f.close
except EIO:
rawMessage(errCannotOpenFile, newFile)
proc `=~`(s: string, a: openArray[string]): bool =
for x in a:
if s.startsWith(x): return true
proc beautifyName(s: string, k: TSymKind): string =
# minimal set of rules here for transition:
# GC_ is allowed
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
if allUpper and k in {skConst, skEnumField, skType}: return s
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# Types should start with a capital unless builtins like 'int' etc.:
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
"range", "openarray", "varargs", "set", "cfloat"
]:
result.add s[i]
else:
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
elif '_' in s: result.add(s[i])
else: result.add toLower(s[0])
inc i
while i < s.len:
if s[i] == '_':
if i > 0 and s[i-1] in {'A'..'Z'}:
# don't skip '_' as it's essential for e.g. 'GC_disable'
result.add('_')
inc i
result.add s[i]
else:
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) =
let beau = beautifyName(s, k)
if s != beau:
message(info, errGenerated, "name should be: " & beau)
const
Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen(line: string, start: int): int =
while start+result < line.len and line[start+result] in Letters:
inc result
proc differ(line: string, a, b: int, x: string): bool =
let y = line[a..b]
result = cmpIgnoreStyle(y, x) == 0 and y != x
when false:
var j = 0
for i in a..b:
if line[i] != x[j]: return true
inc j
return false
proc checkDef*(n: PNode; s: PSym) =
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(n.info, s.name.s, s.kind)
proc checkDef(c: PGen; n: PNode) =
if n.kind != nkSym: return
checkDef(n, n.sym)
proc checkUse*(info: TLineInfo; s: PSym) =
if info.fileIndex < 0: return
# we simply convert it to what it looks like in the definition
# for consistency
# operators stay as they are:
if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
let newName = s.name.s
loadFile(info)
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
var first = min(info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
let last = first+identLen(line, first)-1
if differ(line, first, last, newName):
# last-first+1 != newName.len or
var x = line.substr(0, first-1) & newName & line.substr(last+1)
when removeTP:
# the WinAPI module is full of 'TX = X' which after the substitution
# becomes 'X = X'. We remove those lines:
if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"):
x = ""
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
gSourceFiles[info.fileIndex].dirty = true
when false:
var cannotRename = initIntSet()
proc beautifyName(s: string, k: TSymKind): string =
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
result = newStringOfCap(s.len)
var i = 0
case k
of skType, skGenericParam:
# skip leading 'T'
when removeTP:
if s[0] == 'T' and s[1] in {'A'..'Z'}:
i = 1
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
"char", "byte", "bool", "openArray", "seq", "array", "void",
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
"cshort", "cu"]:
result.add s[i]
else:
result.add toUpper(s[i])
of skConst, skEnumField:
# for 'const' we keep how it's spelt; either upper case or lower case:
result.add s[0]
else:
# as a special rule, don't transform 'L' to 'l'
if s.len == 1 and s[0] == 'L': result.add 'L'
else: result.add toLower(s[0])
inc i
while i < s.len:
if s[i] == '_':
inc i
result.add toUpper(s[i])
elif allUpper:
result.add toLower(s[i])
else:
result.add s[i]
inc i
proc check(c: PGen, n: PNode) =
case n.kind
of nkSym: checkUse(n.info, n.sym)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkDef(c, n[0])
check(c, n.sons[1])
of nkForStmt, nkParForStmt:
let L = n.len
for i in countup(0, L-3):
checkDef(c, n[i])
check(c, n[L-2])
check(c, n[L-1])
of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef,
nkMacroDef, nkConverterDef:
checkDef(c, n[namePos])
for i in namePos+1 .. <n.len: check(c, n.sons[i])
of nkIdentDefs, nkVarTuple:
let a = n
checkMinSonsLen(a, 3)
let L = len(a)
for j in countup(0, L-3): checkDef(c, a.sons[j])
check(c, a.sons[L-2])
check(c, a.sons[L-1])
of nkTypeSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
let a = n.sons[i]
if a.kind == nkCommentStmt: continue
checkSonsLen(a, 3)
checkDef(c, a.sons[0])
check(c, a.sons[1])
check(c, a.sons[2])
else:
for i in 0 .. <n.safeLen: check(c, n.sons[i])
proc processSym(c: PPassContext, n: PNode): PNode =
result = n
check(PGen(c), n)
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on"
result = g
if rules.isNil:
rules = newStringTable(modeStyleInsensitive)
when removeTP:
# XXX activate when the T/P stuff is deprecated
let path = joinPath([getPrefixDir(), "config", "rename.rules.cfg"])
for line in lines(path):
if line.len > 0:
let colon = line.find(':')
if colon > 0:
rules[line.substr(0, colon-1)] = line.substr(colon+1)
else:
rules[line] = line
const prettyPass* = makePass(open = myOpen, process = processSym)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -11,7 +11,7 @@
# This is needed for proper handling of forward declarations.
import
ast, astalgo, msgs, semdata, types, trees
ast, astalgo, msgs, semdata, types, trees, strutils
proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return
@ -68,11 +68,17 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
ExactConstraints, IgnoreCC}
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name)
while result != nil:
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
case equalParams(result.typ.n, fn.typ.n)
of paramsEqual:
if (sfExported notin result.flags) and (sfExported in fn.flags):
let message = ("public implementation '$1' has non-public " &
"forward declaration in $2") %
[getProcHeader(result), $result.info]
localError(fn.info, errGenerated, message)
return
of paramsIncompatible:
localError(fn.info, errNotOverloadable, fn.name.s)

View file

@ -1,4 +1,4 @@
This directory contains the Nimrod compiler written in Nimrod. Note that this
This directory contains the Nim compiler written in Nim. Note that this
code has been translated from a bootstrapping version written in Pascal, so
the code is **not** a poster child of good Nimrod code.
the code is **not** a poster child of good Nim code.

View file

@ -1,13 +1,13 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This module implements the renderer of the standard Nimrod representation.
# This module implements the renderer of the standard Nim representation.
import
lexer, options, idents, strutils, ast, msgs, lists
@ -34,6 +34,7 @@ type
comStack*: seq[PNode] # comment stack
flags*: TRenderFlags
checkAnon: bool # we're in a context that can contain sfAnon
inPragma: int
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
@ -620,7 +621,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c)
gstmts(g, n, c)
put(g, tkCurlyRi, "}")
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
@ -894,8 +895,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(")
for i in countup(0, sonsLen(n) - 1):
if i > 0: put(g, tkOpr, "|")
gsub(g, n.sons[i], c)
put(g, tkParRi, ")")
if n.sons[i].kind == nkSym:
let s = n[i].sym
if s.owner != nil:
put g, tkSymbol, n[i].sym.owner.name.s
put g, tkOpr, "."
put g, tkSymbol, n[i].sym.name.s
else:
gsub(g, n.sons[i], c)
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
of nkPar, nkClosure:
put(g, tkParLe, "(")
gcomma(g, n, c)
@ -940,10 +948,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, -3)
var L = sonsLen(n)
if n.sons[L - 2].kind != nkEmpty:
if L >= 2 and n.sons[L - 2].kind != nkEmpty:
putWithSpace(g, tkColon, ":")
gsub(g, n.sons[L - 2])
if n.sons[L - 1].kind != nkEmpty:
if L >= 1 and n.sons[L - 1].kind != nkEmpty:
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[L - 1], c)
@ -1009,9 +1017,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n.sons[0])
of nkTypeOfExpr:
of nkTypeOfExpr:
putWithSpace(g, tkType, "type")
gsub(g, n.sons[0])
if n.len > 0: gsub(g, n.sons[0])
of nkRefTy:
if sonsLen(n) > 0:
putWithSpace(g, tkRef, "ref")
@ -1177,12 +1185,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkContinueStmt:
putWithSpace(g, tkContinue, "continue")
gsub(g, n.sons[0])
of nkPragma:
of nkPragma:
if renderNoPragmas notin g.flags:
put(g, tkSpaces, Space)
put(g, tkCurlyDotLe, "{.")
gcomma(g, n, emptyContext)
put(g, tkCurlyDotRi, ".}")
if g.inPragma <= 0:
inc g.inPragma
put(g, tkSpaces, Space)
put(g, tkCurlyDotLe, "{.")
gcomma(g, n, emptyContext)
put(g, tkCurlyDotRi, ".}")
dec g.inPragma
else:
gcomma(g, n, emptyContext)
of nkImportStmt, nkExportStmt:
if n.kind == nkImportStmt:
putWithSpace(g, tkImport, "import")
@ -1306,7 +1319,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
proc renderModule(n: PNode, filename: string,
renderFlags: TRenderFlags = {}) =
var
f: TFile
f: File
g: TSrcGen
initSrcGen(g, renderFlags)
for i in countup(0, sonsLen(n) - 1):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -121,7 +121,7 @@ type
r*: string # writers use this
offset*: int # readers use this
TRodReader* = object of TObject
TRodReader* = object of RootObj
pos: int # position; used for parsing
s: cstring # mmap'ed file contents
options: TOptions
@ -137,7 +137,7 @@ type
line: int # only used for debugging, but is always in the code
moduleID: int
syms: TIdTable # already processed symbols
memfile: TMemFile # unfortunately there is no point in time where we
memfile: MemFile # unfortunately there is no point in time where we
# can close this! XXX
methods*: TSymSeq
origFile: string
@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.r = toRope(decodeStr(r.s, r.pos))
else:
loc.r = nil
if r.s[r.pos] == '?':
inc(r.pos)
loc.a = decodeVInt(r.s, r.pos)
else:
loc.a = 0
if r.s[r.pos] == '>': inc(r.pos)
else: internalError(info, "decodeLoc " & r.s[r.pos])
@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
result.size = - 1
if r.s[r.pos] == '=':
inc(r.pos)
result.align = decodeVInt(r.s, r.pos)
result.align = decodeVInt(r.s, r.pos).int16
else:
result.align = 2
decodeLoc(r, result.loc, info)
@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
idTablePut(r.syms, s, s)
strTableAdd(rodCompilerprocs, s)
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) =
var key, val, tmp: int
inc(r.pos, 2) # skip "(\10"
inc(r.line)
@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
new(result)
try:
result.memfile = memfiles.open(modfilename)
except EOS:
except OSError:
return nil
result.files = @[]
result.modDeps = @[]
@ -916,7 +911,7 @@ initIdTable(gTypeTable)
initStrTable(rodCompilerprocs)
# viewer:
proc writeNode(f: TFile; n: PNode) =
proc writeNode(f: File; n: PNode) =
f.write("(")
if n != nil:
f.write($n.kind)
@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) =
writeNode(f, n.sons[i])
f.write(")")
proc writeSym(f: TFile; s: PSym) =
proc writeSym(f: File; s: PSym) =
if s == nil:
f.write("{}\n")
return
@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) =
f.writeNode(s.ast)
f.write("}\n")
proc writeType(f: TFile; t: PType) =
proc writeType(f: File; t: PType) =
if t == nil:
f.write("[]\n")
return

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -187,9 +187,6 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
if loc.r != nil:
add(result, '!')
encodeStr(ropeToStr(loc.r), result)
if loc.a != 0:
add(result, '?')
encodeVInt(loc.a, result)
if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again:
setLen(result, oldLen)
@ -297,7 +294,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
# the last entry of a symbol:
if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if
# it is not necessary, but Nimrod's heavy compile-time evaluation features
# it is not necessary, but Nim's heavy compile-time evaluation features
# make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result)
when false:
@ -422,7 +419,7 @@ proc addStmt(w: PRodWriter, n: PNode) =
proc writeRod(w: PRodWriter) =
processStacks(w, true)
var f: TFile
var f: File
if not open(f, completeGeneratedFilePath(changeFileExt(
w.filename.withPackageName, RodExt)),
fmWrite):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,7 +12,7 @@
# Ropes are a data structure that represents a very long string
# efficiently; especially concatenation is done in O(1) instead of O(N).
# Ropes make use a lazy evaluation: They are essentially concatenation
# trees that are only flattened when converting to a native Nimrod
# trees that are only flattened when converting to a native Nim
# string or when written to disk. The empty string is represented by a
# nil pointer.
# A little picture makes everything clear:
@ -64,7 +64,7 @@ type
# copy the format strings
# though it is not necessary)
PRope* = ref TRope
TRope*{.acyclic.} = object of TObject # the empty rope is represented
TRope*{.acyclic.} = object of RootObj # the empty rope is represented
# by nil to safe space
left*, right*: PRope
length*: int
@ -216,7 +216,7 @@ proc app(a: var PRope, b: PRope) = a = con(a, b)
proc app(a: var PRope, b: string) = a = con(a, b)
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
proc writeRope*(f: TFile, c: PRope) =
proc writeRope*(f: File, c: PRope) =
var stack = @[c]
while len(stack) > 0:
var it = pop(stack)
@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) =
write(f, it.data)
proc writeRope*(head: PRope, filename: string, useWarning = false) =
var f: TFile
var f: File
if open(f, filename, fmWrite):
if head != nil: writeRope(f, head)
close(f)
@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
const
bufSize = 1024 # 1 KB is reasonable
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
if r.data != nil:
if r.length > bufSize:
errorHandler(rTokenTooLong, r.data)
@ -312,7 +312,7 @@ proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
if result: result = auxRopeEqualsFile(r.right, bin, buf)
proc ropeEqualsFile(r: PRope, f: string): bool =
var bin: TFile
var bin: File
result = open(bin, f)
if not result:
return # not equal if file does not exist

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -15,9 +15,12 @@ import
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings
when defined(nimfix):
import nimfix.prettybase
# implementation
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
@ -37,9 +40,7 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
proc addParams(c: PContext, n: PNode, kind: TSymKind)
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode,
flags: TExprFlags = {}, bufferErrors = false): PNode
proc fixImmediateParams(n: PNode): PNode
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
@ -66,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
# error correction:
result = copyTree(arg)
result.typ = formal
else:
let x = result.skipConv
if x.kind == nkPar and formal.kind != tyExpr:
changeType(x, formal, check=true)
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr)
proc isEmptyContainer(t: PType): bool =
case t.kind
of tyExpr, tyNil: result = true
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
of tySet, tySequence, tyOpenArray, tyVarargs:
result = t.sons[0].kind == tyEmpty
of tyGenericInst: result = isEmptyContainer(t.lastSon)
else: result = false
proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors,
# if expressions, etc.:
@ -95,6 +109,13 @@ proc commonType*(x, y: PType): PType =
# check for seq[empty] vs. seq[int]
let idx = ord(b.kind in {tyArray, tyArrayConstr})
if a.sons[idx].kind == tyEmpty: return y
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
var nt: PType
for i in 0.. <a.len:
if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
if nt.isNil: nt = copyType(a, a.owner, false)
nt.sons[i] = b.sons[i]
if not nt.isNil: result = nt
#elif b.sons[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange:
# consider: (range[0..3], range[0..4]) here. We should make that
@ -131,17 +152,14 @@ proc commonType*(x, y: PType): PType =
result = newType(k, r.owner)
result.addSonSkipIntLit(r)
proc isTopLevel(c: PContext): bool {.inline.} =
result = c.currentScope.depthLevel <= 2
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# like newSymS, but considers gensym'ed symbols
if n.kind == nkSym:
# and sfGenSym in n.sym.flags:
result = n.sym
internalAssert sfGenSym in result.flags
internalAssert result.kind == kind
# when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the
@ -308,6 +326,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
pushInfoContext(nOrig.info)
markUsed(n.info, sym)
styleCheckUse(n.info, sym)
if sym == c.p.owner:
globalError(n.info, errRecursiveDependencyX, sym.name.s)
@ -340,7 +359,7 @@ type
TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode
ctx: var IntSet): PNode
include semtypes, semtempl, semgnrc, semstmts, semexprs
@ -367,6 +386,8 @@ proc myOpen(module: PSym): PPassContext =
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
c.instDeepCopy = sigmatch.instDeepCopy
pushProcCon(c, module)
pushOwner(c.module)
c.importTable = openScope(c)

197
compiler/semasgn.nim Normal file
View file

@ -0,0 +1,197 @@
#
#
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements lifting for assignments and ``deepCopy``.
# included from sem.nim
type
TLiftCtx = object
c: PContext
info: TLineInfo # for construction
result: PNode
kind: TTypeAttachedOp
type
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
tupleType: PType # if != nil we're traversing a tuple
tupleIndex: int
field: PSym
replaceByFieldName: bool
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent:
result = n
var L = sonsLen(forLoop)
if c.replaceByFieldName:
if n.ident.id == forLoop[0].ident.id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
result = newStrNode(nkStrLit, fieldName)
return
# other fields:
for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, c.tupleIndex))
else:
result = newNodeI(nkDotExpr, n.info)
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1):
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) =
case typ.kind
of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(semStmt(c.c, body))
dec c.c.inUnrolledContext
closeScope(c.c)
of nkNilLit: discard
of nkRecCase:
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
localError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
asgnForObjectFields(c, typ[0], forLoop, father)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, c.info)
# generate selector:
var access = newNodeI(nkDotExpr, forLoop.info, 2)
access.sons[0] = call.sons[1]
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
caseStmt.add(semExprWithType(c.c, access))
# copy the branches over, but replace the fields with the for loop body:
for i in 1 .. <typ.len:
var branch = copyTree(typ[i])
let L = branch.len
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
caseStmt.add(branch)
father.add(caseStmt)
of nkRecList:
for t in items(typ): liftBodyObj(c, t, x, y)
else:
illFormedAst(typ)
proc newAsgnCall(op: PSym; x, y: PNode): PNode =
result = newNodeI(nkCall, x.info)
result.add(newSymNode(op))
result.add x
result.add y
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri
proc newDestructorCall(op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ.sons[0])
result.add(newSymNode(op))
result.add x
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newDestructorCall(op, y))
proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool =
let op = t.attachedOps[c.kind]
if op != nil:
markUsed(c.info, op)
styleCheckUse(c.info, op)
case c.kind
of attachedDestructor:
c.result.add newDestructorCall(op, x)
of attachedAsgn:
c.result.add newAsgnCall(op, x, y)
of attachedDeepCopy:
c.result.add newDeepCopyCall(op, x, y)
result = true
proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) =
if c.kind != attachedDestructor:
c.result.add newAsgnStmt(x, y)
proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [
(proc (t: PType, closure: PObject): bool =
t.attachedOp[attachedDestructor] != nil),
(proc (t: PType, closure: PObject): bool =
t.attachedOp[attachedAsgn] != nil),
(proc (t: PType, closure: PObject): bool =
t.attachedOp[attachedDeepCopy] != nil)]
case t.kind
of tyNone, tyEmpty: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString:
defaultOp(c, t, x, y)
of tyPtr, tyString:
if not considerOverloadedOp(c, t, x, y):
defaultOp(c, t, x, y)
of tyArrayConstr, tyArray, tySequence:
if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil):
# generate loop and call the attached Op:
else:
defaultOp(c, t, x, y)
of tyObject:
liftBodyObj(c, t.n, x, y)
of tyTuple:
liftBodyTup(c, t, x, y)
of tyRef:
# we MUST not check for acyclic here as a DAG might still share nodes:
of tyProc:
if t.callConv != ccClosure or c.kind != attachedDeepCopy:
defaultOp(c, t, x, y)
else:
# a big problem is that we don't know the enviroment's type here, so we
# have to go through some indirection; we delegate this to the codegen:
call = newNodeI(nkCall, n.info, 2)
call.typ = t
call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
call.sons[1] = y
c.result.add newAsgnStmt(x, call)
of tyVarargs, tyOpenArray:
localError(c.info, errGenerated, "cannot copy openArray")
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward:
internalError(c.info, "assignment requested for type: " & typeToString(t))
of tyDistinct, tyOrdinal, tyRange,
tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
liftBodyAux(c, lastSon(t))
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode =
var a: TLiftCtx
a.info = info
a.result = newNodeI(nkStmtList, info)
liftBodyAux(a, typ)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
initialBinding: PNode,
filter: TSymKinds,
best, alt: var TCandidate,
errors: var seq[string]) =
errors: var CandidateErrors) =
var o: TOverloadIter
var sym = initOverloadIter(o, c, headSymbol)
var symScope = o.lastOverloadScope
@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
z.calleeSym = sym
matches(c, n, orig, z)
if errors != nil:
errors.safeAdd(getProcHeader(sym))
errors.safeAdd(sym)
if z.errors != nil:
for err in z.errors:
errors[errors.len - 1].add("\n " & err)
errors.add(err)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind in skIterators: inc(z.exactMatches, 200)
@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
else: discard
sym = nextOverloadIter(o, c, headSymbol)
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
@ -83,18 +83,38 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
globalError(n.info, errTypeMismatch, "")
if errors.len == 0:
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1))
add(result, ')')
# to avoid confusing errors like:
# got (SslPtr, SocketHandle)
# but expected one of:
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
# we do a pre-analysis. If all types produce the same string, we will add
# module information.
let proto = describeArgs(c, n, 1, preferName)
var prefer = preferName
for err in errors:
var errProto = ""
let n = err.typ.n
for i in countup(1, n.len - 1):
var p = n.sons[i]
if p.kind == nkSym:
add(errProto, typeToString(p.sym.typ, preferName))
if i != n.len-1: add(errProto, ", ")
# else: ignore internal error as we're already in error handling mode
if errProto == proto:
prefer = preferModuleInfo
break
# now use the information stored in 'prefer' to produce a nice error message:
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1, prefer))
add(result, ')')
var candidates = ""
for err in errors:
add(candidates, err)
add(candidates, err.getProcHeader(prefer))
add(candidates, "\n")
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
localError(n.info, errGenerated, result)
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
@ -114,7 +134,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else:
initialBinding = nil
var errors: seq[string]
var errors: CandidateErrors
var usedSyms: seq[PNode]
template pickBest(headSymbol: expr) =
@ -254,6 +274,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
var finalCallee = x.calleeSym
markUsed(n.sons[0].info, finalCallee)
styleCheckUse(n.sons[0].info, finalCallee)
if finalCallee.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
@ -286,6 +307,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(newInst, n.info)
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
@ -305,7 +327,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = explicitGenericSym(c, n, s)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
# It's good enough for now.
result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1):

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -57,7 +57,7 @@ type
# can access private object fields
instCounter*: int # to prevent endless instantiations
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!)
inTypeClass*: int # > 0 if we are in a user-defined type class
inGenericContext*: int # > 0 if we are in a generic type
@ -72,8 +72,7 @@ type
libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
bufferErrors = false): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
@ -83,15 +82,18 @@ type
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files
includedFiles*: IntSet # used to detect recursive include files
userPragmas*: TStrTable
evalContext*: PEvalContext
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
# naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
info: TLineInfo): PSym {.nimcall.}
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s
@ -310,3 +312,8 @@ proc checkSonsLen*(n: PNode, length: int) =
proc checkMinSonsLen*(n: PNode, length: int) =
if sonsLen(n) < length: illFormedAst(n)
proc isTopLevel*(c: PContext): bool {.inline.} =
result = c.currentScope.depthLevel <= 2
proc experimentalMode*(c: PContext): bool {.inline.} =
result = gExperimentalMode or sfExperimental in c.module.flags

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -13,6 +13,7 @@
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode =
markUsed(n.info, s)
styleCheckUse(n.info, s)
pushInfoContext(n.info)
result = evalTemplate(n, s, getCurrOwner())
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
@ -79,6 +80,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind
of skConst:
markUsed(n.info, s)
styleCheckUse(n.info, s)
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64:
@ -103,6 +105,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of skTemplate: result = semTemplateExpr(c, n, s, flags)
of skVar, skLet, skResult, skParam, skForVar:
markUsed(n.info, s)
styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect)
@ -115,6 +118,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam:
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic:
result = newSymNode(s, n.info)
result.typ = s.typ
@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
return n
of skType:
markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
else:
markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info)
type
@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
let status = checkConvertible(c, result.typ, it.typ)
if status in {convOK, convNotNeedeed}:
markUsed(n.info, it.sym)
styleCheckUse(n.info, it.sym)
markIndirect(c, it.sym)
return it
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
@ -360,6 +367,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator notin t.flags))
else: discard
else:
var t2 = n[2].typ.skipTypes({tyTypeDesc})
maybeLiftType(t2, c, n.info)
@ -415,34 +423,22 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
result = semExpr(c, result)
proc changeType(n: PNode, newType: PType, check: bool) =
proc changeType(n: PNode, newType: PType, check: bool) =
case n.kind
of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1):
of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType), check)
of nkPar:
if newType.kind != tyTuple:
of nkPar:
let tup = newType.skipTypes({tyGenericInst})
if tup.kind != tyTuple:
internalError(n.info, "changeType: no tuple type for constructor")
elif newType.n == nil: discard
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i].sons[0]
if m.kind != nkSym:
internalError(m.info, "changeType(): invalid tuple constr")
return
var f = getSymFromList(newType.n, m.sym.name)
if f == nil:
internalError(m.info, "changeType(): invalid identifier")
return
changeType(n.sons[i].sons[1], f.typ, check)
else:
for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m)
changeType(m, newType.sons[i], check)
n.sons[i] = a
if m.kind == nkExprColonExpr:
m = m.sons[1]
n.sons[i] = m
changeType(m, tup.sons[i], check)
of nkCharLit..nkUInt64Lit:
if check:
let value = n.intVal
@ -533,7 +529,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar)
changeType(it.sons[1], s, check=true)
if s.kind != tyExpr:
changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1]
of nkBracket:
# an implicitly constructed array (passed to an open array):
@ -721,7 +718,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
case callee.kind
of skMacro, skTemplate: discard
else:
if (callee.kind in skIterators) and (callee.id == c.p.owner.id):
if callee.kind in skIterators and callee.id == c.p.owner.id:
localError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}:
@ -832,45 +829,17 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
if result != nil: result = afterCallActions(c, result, nOrig, flags)
else: result = errorNode(c, n)
proc buildStringify(c: PContext, arg: PNode): PNode =
if arg.typ != nil and
skipTypes(arg.typ, abstractInst-{tyTypeDesc}).kind == tyString:
result = arg
else:
result = newNodeI(nkCall, arg.info)
addSon(result, newIdentNode(getIdent"$", arg.info))
addSon(result, arg)
proc semEcho(c: PContext, n: PNode): PNode =
# this really is a macro
checkMinSonsLen(n, 1)
for i in countup(1, sonsLen(n) - 1):
var arg = semExprWithType(c, n.sons[i])
arg = semExprWithType(c, buildStringify(c, arg))
n.sons[i] = arg
let t = arg.typ
if (t == nil or t.skipTypes(abstractInst).kind != tyString) and
arg.kind != nkEmpty:
localError(n.info, errGenerated,
"implicitly invoked '$' does not return string")
let t = n.sons[0].typ
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
result = n
proc buildEchoStmt(c: PContext, n: PNode): PNode =
# we MUST not check 'n' for semantics again here!
# we MUST not check 'n' for semantics again here! But for now we give up:
result = newNodeI(nkCall, n.info)
var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
if e != nil:
addSon(result, newSymNode(e))
add(result, newSymNode(e))
else:
localError(n.info, errSystemNeeds, "echo")
addSon(result, errorNode(c, n))
var arg = buildStringify(c, n)
# problem is: implicit '$' is not checked for semantics yet. So we give up
# and check 'arg' for semantics again:
arg = semExpr(c, arg)
if arg != nil: addSon(result, arg)
add(result, errorNode(c, n))
add(result, n)
result = semExpr(c, result)
proc semExprNoType(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {efWantStmt})
@ -958,17 +927,18 @@ proc readTypeParameter(c: PContext, typ: PType,
paramName: PIdent, info: TLineInfo): PNode =
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
#debug ty
let tbody = ty.sons[0]
for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s]
if tParam.sym.name == paramName:
if tParam.sym.name.id == paramName.id:
let rawTyp = ty.sons[s + 1]
if rawTyp.kind == tyStatic:
return rawTyp.n
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
#echo "came here: returned nil"
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access
@ -980,8 +950,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if s != nil:
markUsed(n.sons[1].info, s)
return semSym(c, n, s, flags)
if s.kind in OverloadableSyms:
result = symChoice(c, n, s, scClosed)
if result.kind == nkSym: result = semSym(c, n, s, flags)
else:
markUsed(n.sons[1].info, s)
result = semSym(c, n, s, flags)
styleCheckUse(n.sons[1].info, s)
return
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
#restoreOldStyleType(n.sons[0])
@ -997,13 +973,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# look up if the identifier belongs to the enum:
while ty != nil:
f = getSymFromList(ty.n, i)
if f != nil: break
if f != nil: break
ty = ty.sons[0] # enum inheritance
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(n.info, f)
styleCheckUse(n.info, f)
return
of tyTypeParamsHolders:
return readTypeParameter(c, ty, i, n.info)
@ -1036,12 +1013,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
if fieldVisible(c, f):
# is the access to a public field or in the same module or in a friend?
markUsed(n.sons[1].info, f)
styleCheckUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f) # we now have the correct field
n.typ = f.typ
if check == nil:
if check == nil:
result = n
else:
else:
check.sons[0] = n
check.typ = n.typ
result = check
@ -1049,6 +1027,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
f = getSymFromList(ty.n, i)
if f != nil:
markUsed(n.sons[1].info, f)
styleCheckUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f)
n.typ = f.typ
@ -1260,8 +1239,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
proc semReturn(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1)
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
c.p.owner.kind == skClosureIterator:
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
skClosureIterator}:
if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil:
@ -1444,6 +1423,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
proc semUsing(c: PContext, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info)
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
for e in n.sons:
let usedSym = semExpr(c, e)
if usedSym.kind == nkSym:
@ -1465,6 +1446,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
markUsed(n.info, expandedSym)
styleCheckUse(n.info, expandedSym)
for i in countup(1, macroCall.len-1):
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
@ -1525,11 +1507,11 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
if ids.len > 0:
doBlk[paramsPos].sons.setLen(2)
doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
ids.add getSysSym("expr").newSymNode # params type
ids.add emptyNode # no default value
doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids)
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
var tmpl = semTemplateDef(c, doBlk)
quotes[0] = tmpl[namePos]
@ -1538,8 +1520,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
newNode(nkCall, n.info, quotes)])
result = semExpandToAst(c, result)
proc tryExpr(c: PContext, n: PNode,
flags: TExprFlags = {}, bufferErrors = false): PNode =
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
@ -1553,7 +1534,7 @@ proc tryExpr(c: PContext, n: PNode,
let oldOwnerLen = len(gOwners)
let oldGenerics = c.generics
let oldErrorOutputs = errorOutputs
errorOutputs = if bufferErrors: {eInMemory} else: {}
errorOutputs = {}
let oldContextLen = msgs.getInfoContextLen()
let oldInGenericContext = c.inGenericContext
@ -1638,7 +1619,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mSizeOf: result = semSizeof(c, setMs(n, s))
of mIs: result = semIs(c, setMs(n, s))
of mOf: result = semOf(c, setMs(n, s))
of mEcho: result = semEcho(c, setMs(n, s))
of mShallowCopy: result = semShallowCopy(c, n, flags)
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
of mQuoteAst: result = semQuoteAst(c, n)
@ -1662,6 +1642,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else:
result.typ = result[1].typ
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
of mProcCall:
result = setMs(n, s)
result.sons[1] = semExpr(c, n.sons[1])
result.typ = n[1].typ
else: result = semDirectOp(c, n, flags)
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
@ -1821,7 +1805,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
addSonSkipIntLit(typ, n.sons[i].typ)
result.typ = typ
proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) =
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
@ -1902,6 +1886,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
addDecl(c, labl)
n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(n.sons[0].info, labl)
styleCheckDef(labl)
n.sons[1] = semExpr(c, n.sons[1])
n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt
@ -1909,19 +1894,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
closeScope(c)
dec(c.p.nestedBlockCounter)
proc doBlockIsStmtList(n: PNode): bool =
result = n.kind == nkDo and
n[paramsPos].sonsLen == 1 and
n[paramsPos][0].kind == nkEmpty
proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out
# the planned overload resolution reforms
for i in 1 .. <safeLen(n):
if doBlockIsStmtList(n[i]):
n.sons[i] = n[i][bodyPos]
result = n
proc semExport(c: PContext, n: PNode): PNode =
var x = newNodeI(n.kind, n.info)
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
@ -1930,13 +1902,23 @@ proc semExport(c: PContext, n: PNode): PNode =
var o: TOverloadIter
var s = initOverloadIter(o, c, a)
if s == nil:
localError(a.info, errGenerated, "invalid expr for 'export': " &
renderTree(a))
while s != nil:
if s.kind in ExportableSymKinds+{skModule}:
x.add(newSymNode(s, a.info))
strTableAdd(c.module.tab, s)
s = nextOverloadIter(o, c, a)
localError(a.info, errGenerated, "cannot export: " & renderTree(a))
elif s.kind == skModule:
# forward everything from that module:
strTableAdd(c.module.tab, s)
x.add(newSymNode(s, a.info))
var ti: TTabIter
var it = initTabIter(ti, s.tab)
while it != nil:
if it.kind in ExportableSymKinds+{skModule}:
strTableAdd(c.module.tab, it)
it = nextIter(ti, s.tab)
else:
while s != nil:
if s.kind in ExportableSymKinds+{skModule}:
x.add(newSymNode(s, a.info))
strTableAdd(c.module.tab, s)
s = nextOverloadIter(o, c, a)
when false:
if c.module.ast.isNil:
c.module.ast = newNodeI(nkStmtList, n.info)
@ -2021,22 +2003,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 1)
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
var s = qualifiedLookUp(c, n.sons[0], mode)
if s != nil:
if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
pretty.checkUse(n.sons[0].sons[1].info, s)
if s != nil:
#if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
# pretty.checkUse(n.sons[0].sons[1].info, s)
case s.kind
of skMacro:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
var p = fixImmediateParams(n)
result = semMacroExpr(c, p, p, s, flags)
result = semMacroExpr(c, n, n, s, flags)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
var p = fixImmediateParams(n)
result = semTemplateExpr(c, p, s, flags)
result = semTemplateExpr(c, n, s, flags)
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:

163
compiler/semfields.nim Normal file
View file

@ -0,0 +1,163 @@
#
#
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module does the semantic transformation of the fields* iterators.
# included from semstmts.nim
type
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
tupleType: PType # if != nil we're traversing a tuple
tupleIndex: int
field: PSym
replaceByFieldName: bool
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent:
result = n
var L = sonsLen(forLoop)
if c.replaceByFieldName:
if n.ident.id == forLoop[0].ident.id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
result = newStrNode(nkStrLit, fieldName)
return
# other fields:
for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, c.tupleIndex))
else:
result = newNodeI(nkDotExpr, n.info)
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1):
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
type
TFieldsCtx = object
c: PContext
m: TMagic
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
case typ.kind
of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(semStmt(c.c, body))
dec c.c.inUnrolledContext
closeScope(c.c)
of nkNilLit: discard
of nkRecCase:
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
localError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
semForObjectFields(c, typ[0], forLoop, father)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
# generate selector:
var access = newNodeI(nkDotExpr, forLoop.info, 2)
access.sons[0] = call.sons[1]
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
caseStmt.add(semExprWithType(c.c, access))
# copy the branches over, but replace the fields with the for loop body:
for i in 1 .. <typ.len:
var branch = copyTree(typ[i])
let L = branch.len
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
caseStmt.add(branch)
father.add(caseStmt)
of nkRecList:
for t in items(typ): semForObjectFields(c, t, forLoop, father)
else:
illFormedAst(typ)
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
if trueSymbol == nil:
localError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool)
result.sons[0] = newSymNode(trueSymbol, n.info)
var stmts = newNodeI(nkStmtList, n.info)
result.sons[1] = stmts
var length = sonsLen(n)
var call = n.sons[length-2]
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
localError(n.info, errWrongNumberOfVariables)
return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1:
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
if not sameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
inc(c.p.nestedLoopCounter)
if tupleTypeA.kind == tyTuple:
var loopBody = n.sons[length-1]
for i in 0..sonsLen(tupleTypeA)-1:
openScope(c)
var fc: TFieldInstCtx
fc.tupleType = tupleTypeA
fc.tupleIndex = i
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.inUnrolledContext
stmts.add(semStmt(c, body))
dec c.inUnrolledContext
closeScope(c)
else:
var fc: TFieldsCtx
fc.m = m
fc.c = c
var t = tupleTypeA
while t.kind == tyObject:
semForObjectFields(fc, t.n, n, stmts)
if t.sons[0] == nil: break
t = skipTypes(t.sons[0], abstractPtrs)
dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so
# we avoid it now if we can:
if hasSonWith(stmts, nkBreakStmt):
var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode)
stmts.add(b)
else:
result = stmts

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -197,18 +197,20 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
of mSubI, mSubI64, mSubU:
binaryOp(`|-|`)
of mBitandI, mBitandI64:
# since uint64 is still not even valid for 'range' (since it's no ordinal
# yet), we exclude it from the list (see bug #1638) for now:
var a = n.sons[1]
var b = n.sons[2]
# symmetrical:
if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b)
if b.kind in {nkIntLit..nkUInt64Lit}:
if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
if b.kind in {nkIntLit..nkUInt32Lit}:
let x = b.intVal|+|1
if (x and -x) == x and x >= 0:
result = makeRange(a.typ, 0, b.intVal)
of mModU:
let a = n.sons[1]
let b = n.sons[2]
if b.kind in {nkIntLit..nkUInt64Lit}:
if b.kind in {nkIntLit..nkUInt32Lit}:
if b.intVal >= 0:
result = makeRange(a.typ, 0, b.intVal-1)
else:
@ -255,6 +257,7 @@ proc evalIs(n, a: PNode): PNode =
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and
tfIterator in t.flags))
else: discard
else:
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
let t2 = n[2].typ
@ -318,8 +321,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: internalError(n.info, "constant folding for shr")
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
of mDivI, mDivI64:
let y = getInt(b)
if y != 0:
result = newIntNodeT(getInt(a) div y, n)
of mModI, mModI64:
let y = getInt(b)
if y != 0:
result = newIntNodeT(getInt(a) mod y, n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
@ -358,8 +367,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
of mModU:
let y = getInt(b)
if y != 0:
result = newIntNodeT(`%%`(getInt(a), y), n)
of mDivU:
let y = getInt(b)
if y != 0:
result = newIntNodeT(`/%`(getInt(a), y), n)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
of mLtSet:
@ -501,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64:
result = newIntNodeT(system.toInt(getFloat(a)), n)
result = newIntNodeT(int(getFloat(a)), n)
of tyChar: result = newIntNodeT(getOrdValue(a), n)
else:
result = a
@ -600,10 +615,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
of mNimrodVersion: result = newStrNodeT(VersionAsString, n)
of mNimrodMajor: result = newIntNodeT(VersionMajor, n)
of mNimrodMinor: result = newIntNodeT(VersionMinor, n)
of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
@ -683,9 +694,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = evalIs(n, a)
else:
result = magicCall(m, n)
except EOverflow:
except OverflowError:
localError(n.info, errOverOrUnderflow)
except EDivByZero:
except DivByZeroError:
localError(n.info, errConstantDivisionByZero)
of nkAddr:
var a = getConstExpr(m, n.sons[0])

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -13,7 +13,7 @@
# A problem is that it cannot be detected if the symbol is introduced
# as in ``var x = ...`` or used because macros/templates can hide this!
# So we have to eval templates/macros right here so that symbol
# lookup can be accurate. XXX But this can only be done for immediate macros!
# lookup can be accurate.
# included from sem.nim
@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode =
proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
ctx: var IntSet): PNode =
openScope(c)
result = semGenericStmt(c, n, flags, ctx)
closeScope(c)
@ -37,7 +37,7 @@ template macroToExpand(s: expr): expr =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var TIntSet): PNode =
ctx: var IntSet): PNode =
incl(s.flags, sfUsed)
case s.kind
of skUnknown:
@ -47,33 +47,39 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
styleCheckUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
of skMacro:
if macroToExpand(s):
styleCheckUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
else:
result = symChoice(c, n, s, scOpen)
of skGenericParam:
result = newSymNodeTypeDesc(s, n.info)
of skParam:
styleCheckUse(n.info, s)
of skParam:
result = n
styleCheckUse(n.info, s)
of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNodeTypeDesc(s, n.info)
else:
result = n
else: result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else:
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
ctx: var IntSet): PNode =
result = n
let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident)
var s = searchInScopes(c, ident).skipAlias(n)
if s == nil:
if ident.id notin ctx and withinMixin notin flags:
localError(n.info, errUndeclaredIdentifier, ident.s)
@ -92,7 +98,7 @@ proc newDot(n, b: PNode): PNode =
result.add(b)
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode =
ctx: var IntSet; isMacro: var bool): PNode =
assert n.kind == nkDotExpr
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
@ -104,8 +110,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
result = n
let n = n[1]
let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident)
var s = searchInScopes(c, ident).skipAlias(n)
if s != nil and s.kind in routineKinds:
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags:
result = newDot(result, symChoice(c, n, s, scClosed))
elif s.name.id in ctx:
@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
else:
result = newDot(result, sym)
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(n), c)
addPrelimDecl(c, s)
styleCheckDef(n.info, s, kind)
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var TIntSet): PNode =
flags: TSemGenericFlags, ctx: var IntSet): PNode =
result = n
if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind
@ -129,7 +141,8 @@ proc semGenericStmt(c: PContext, n: PNode,
#var s = qualifiedLookUp(c, n, luf)
#if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
result = fuzzyLookup(c, n, flags, ctx)
var dummy: bool
result = fuzzyLookup(c, n, flags, ctx, dummy)
of nkEmpty, nkSym..nkNilLit:
# see tests/compile/tgensymgeneric.nim:
# We need to open the gensym'ed symbol again so that the instantiation
@ -153,50 +166,61 @@ proc semGenericStmt(c: PContext, n: PNode,
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
var first = 0
var isDefinedMagic = false
if s != nil:
var mixinContext = false
if s != nil:
incl(s.flags, sfUsed)
isDefinedMagic = s.magic in {mDefined, mDefinedInScope, mCompiles}
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
let scOption = if s.name.id in ctx: scForceOpen else: scOpen
case s.kind
of skMacro:
if macroToExpand(s):
styleCheckUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
n.sons[0] = symChoice(c, fn, s, scOption)
result = n
of skTemplate:
mixinContext = true
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
styleCheckUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx)
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
n.sons[0] = symChoice(c, fn, s, scOption)
result = n
# BUGFIX: we must not return here, we need to do first phase of
# symbol lookup ...
# symbol lookup. Also since templates and macros can do scope injections
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
# the famous "undeclared identifier: it" bug:
mixinContext = true
of skUnknown, skParam:
# Leave it as an identifier.
discard
of skProc, skMethod, skIterators, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
result.sons[0] = symChoice(c, fn, s, scOption)
first = 1
of skGenericParam:
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s)
first = 1
of skType:
# bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s)
first = 1
else:
result.sons[0] = newSymNode(s, n.sons[0].info)
result.sons[0] = newSymNode(s, fn.info)
styleCheckUse(fn.info, s)
first = 1
elif fn.kind == nkDotExpr:
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
first = 1
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
# is not exported and yet the generic 'threadProcWrapper' works correctly.
let flags = if isDefinedMagic: flags+{withinMixin} else: flags
let flags = if mixinContext: flags+{withinMixin} else: flags
for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
of nkIfStmt:
@ -226,14 +250,14 @@ proc semGenericStmt(c: PContext, n: PNode,
openScope(c)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
for i in countup(0, L - 3):
addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c))
addTempDecl(c, n.sons[i], skForVar)
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
closeScope(c)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
openScope(c)
if n.sons[0].kind != nkEmpty:
addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c))
addTempDecl(c, n.sons[0], skLabel)
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
closeScope(c)
of nkTryStmt:
@ -256,7 +280,7 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
@ -266,23 +290,23 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
addTempDecl(c, getIdentNode(a.sons[j]), skType)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
of nkTypeSection:
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
addTempDecl(c, getIdentNode(a.sons[0]), skType)
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
@ -306,9 +330,9 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
of nkObjectTy, nkTupleTy:
of nkObjectTy, nkTupleTy:
discard
of nkFormalParams:
of nkFormalParams:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
@ -320,17 +344,17 @@ proc semGenericStmt(c: PContext, n: PNode,
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambdaKinds:
checkSonsLen(n, bodyPos + 1)
if n.kind notin nkLambdaKinds:
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
if n.sons[namePos].kind != nkEmpty:
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
openScope(c)
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
flags, ctx)
if n.sons[paramsPos].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty:
if n.sons[paramsPos].sons[0].kind != nkEmpty:
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -157,8 +157,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
#
# The solution would be to move this logic into semtypinst, but
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc
#
# will need to use openScope, addDecl, etc.
addDecl(c, prc)
pushInfoContext(info)
@ -223,7 +222,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
n.sons[genericParamsPos] = ast.emptyNode
var oldPrc = genericCacheGet(fn, entry[])
if oldPrc == nil:
fn.procInstCache.safeAdd(entry)
# we MUST not add potentially wrong instantiations to the caching mechanism.
# This means recursive instantiations behave differently when in
# a ``compiles`` context but this is the lesser evil. See
# bug #1055 (tevilcompiles).
if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry))
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -55,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) =
else:
globalError(n.info, "() must have an object or tuple type")
of nkBracket:
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -130,4 +130,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
else: result = n

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -258,14 +258,18 @@ proc min(a, b: PNode): PNode =
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
inc c.spawns
let oldSpawnId = c.currentSpawnId
c.currentSpawnId = c.spawns
body
c.currentSpawnId = oldSpawnId
proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
if op.magic == mSpawn:
inc c.spawns
let oldSpawnId = c.currentSpawnId
c.currentSpawnId = c.spawns
gatherArgs(c, n[1])
analyseSons(c, n)
c.currentSpawnId = oldSpawnId
pushSpawnId(c):
gatherArgs(c, n[1])
analyseSons(c, n)
elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
if n[1].isLocal:
let incr = n[2].skipConv
@ -320,9 +324,16 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
# since we already ensure sfAddrTaken is not in s.flags, we only need to
# prevent direct assignments to the monotonic variable:
let slot = c.getSlot(n[0].sym)
slot.blackListed = true
slot.blacklisted = true
invalidateFacts(c.guards, n[0])
analyseSons(c, n)
let value = n[1]
if getMagic(value) == mSpawn:
pushSpawnId(c):
gatherArgs(c, value[1])
analyseSons(c, value[1])
analyse(c, n[0])
else:
analyseSons(c, n)
addAsgnFact(c.guards, n[0], n[1])
of nkCallKinds:
# direct call:
@ -335,16 +346,21 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
localError(n.info, "invalid control flow for 'parallel'")
# 'break' that leaves the 'parallel' section is not valid either
# or maybe we should generate a 'try' XXX
of nkVarSection:
of nkVarSection, nkLetSection:
for it in n:
let value = it.lastSon
let isSpawned = getMagic(value) == mSpawn
if isSpawned:
pushSpawnId(c):
gatherArgs(c, value[1])
analyseSons(c, value[1])
if value.kind != nkEmpty:
for j in 0 .. it.len-3:
if it[j].isLocal:
let slot = c.getSlot(it[j].sym)
if slot.lower.isNil: slot.lower = value
else: internalError(it.info, "slot already has a lower bound")
analyse(c, value)
if not isSpawned: analyse(c, value)
of nkCaseStmt: analyseCase(c, n)
of nkIfStmt, nkIfExpr: analyseIf(c, n)
of nkWhileStmt:
@ -396,7 +412,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
case n.kind
of nkVarSection:
of nkVarSection, nkLetSection:
result = nil
for it in n:
let b = it.lastSon
@ -464,6 +480,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
generateAliasChecks(a, result)
result.add varSection
result.add callCodeGenProc("openBarrier", barrier)
result.add callCodegenProc("openBarrier", barrier)
result.add transformSpawn(owner, body, barrier)
result.add callCodeGenProc("closeBarrier", barrier)
result.add callCodegenProc("closeBarrier", barrier)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -57,30 +57,125 @@ discard """
c()
--> we need a stack of scopes for this analysis
"""
const trackGlobals = false ## we don't need it for now
# XXX enhance the algorithm to care about 'dirty' expressions:
lock a[i].L:
inc i # mark 'i' dirty
lock a[j].L:
access a[i], a[j] # --> reject a[i]
"""
type
TEffects = object
exc: PNode # stack of exceptions
tags: PNode # list of tags
uses: PNode # list of used global variables
bottom: int
bottom, inTryStmt: int
owner: PSym
init: seq[int] # list of initialized variables
guards: TModel # nested guards
locked: seq[PNode] # locked locations
gcUnsafe, isRecursive: bool
gcUnsafe, isRecursive, isToplevel: bool
maxLockLevel, currLockLevel: TLockLevel
PEffects = var TEffects
proc `<`(a, b: TLockLevel): bool {.borrow.}
proc `<=`(a, b: TLockLevel): bool {.borrow.}
proc `==`(a, b: TLockLevel): bool {.borrow.}
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
proc isLocalVar(a: PEffects, s: PSym): bool =
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
proc initVar(a: PEffects, n: PNode) =
proc getLockLevel(t: PType): TLockLevel =
var t = t
# tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
result = t.n.intVal.TLockLevel
proc lockLocations(a: PEffects; pragma: PNode) =
if pragma.kind != nkExprColonExpr:
localError(pragma.info, errGenerated, "locks pragma without argument")
return
var firstLL = TLockLevel(-1'i16)
for x in pragma[1]:
let thisLL = getLockLevel(x.typ)
if thisLL != 0.TLockLevel:
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
localError(x.info, "invalid lock level: " & $thisLL)
elif firstLL < 0.TLockLevel: firstLL = thisLL
elif firstLL != thisLL:
localError(x.info, errGenerated,
"multi-lock requires the same static lock level for every operand")
a.maxLockLevel = max(a.maxLockLevel, firstLL)
a.locked.add x
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
localError(pragma.info, errGenerated,
"invalid nested locking")
a.currLockLevel = firstLL
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
# check whether the corresponding lock is held:
for L in a.locked:
if L.kind == nkSym and L.sym == guard: return
# we allow accesses nevertheless in top level statements for
# easier initialization:
#if a.isTopLevel:
# message(n.info, warnUnguardedAccess, renderTree(n))
#else:
if not a.isTopLevel:
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
# 'guard*' are checks which are concerned with 'guard' annotations
# (var x{.guard: y.}: int)
proc guardDotAccess(a: PEffects; n: PNode) =
let ri = n.sons[1]
if ri.kind != nkSym or ri.sym.kind != skField: return
var g = ri.sym.guard
if g.isNil or a.isTopLevel: return
# fixup guard:
if g.kind == skUnknown:
var field: PSym = nil
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
if ty.kind == tyTuple:
field = lookupInRecord(ty.n, g.name)
else:
while ty != nil and ty.kind == tyObject:
field = lookupInRecord(ty.n, g.name)
if field != nil: break
ty = ty.sons[0]
if ty == nil: break
ty = ty.skipTypes(abstractPtrs)
if field == nil:
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
return
g = field
#ri.sym.guard = field
# XXX unfortunately this is not correct for generic instantiations!
if g.kind == skField:
let dot = newNodeI(nkDotExpr, n.info, 2)
dot.sons[0] = n.sons[0]
dot.sons[1] = newSymNode(g)
dot.typ = g.typ
for L in a.locked:
#if a.guards.sameSubexprs(dot, L): return
if guards.sameTree(dot, L): return
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
else:
guardGlobal(a, n, g)
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
template compileToCpp(a): expr =
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
if a.inTryStmt > 0 and not compileToCpp(a):
incl(s.flags, sfVolatile)
proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
if n.kind != nkSym: return
let s = n.sym
if isLocalVar(a, s):
if volatileCheck: makeVolatile(a, s)
for x in a.init:
if x == s.id: return
a.init.add s.id
@ -91,14 +186,13 @@ proc initVarViaNew(a: PEffects, n: PNode) =
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
# 'x' is not nil, but that doesn't mean its "not nil" children
# are initialized:
initVar(a, n)
initVar(a, n, volatileCheck=true)
elif isLocalVar(a, s):
makeVolatile(a, s)
when trackGlobals:
proc addUse(a: PEffects, e: PNode) =
var aa = a.uses
for i in 0 .. <aa.len:
if aa[i].sym.id == e.sym.id: return
a.uses.add(e)
proc warnAboutGcUnsafe(n: PNode) =
#assert false
message(n.info, warnGcUnsafe, renderTree(n))
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
@ -110,12 +204,11 @@ proc useVar(a: PEffects, n: PNode) =
message(n.info, warnUninit, s.name.s)
# prevent superfluous warnings about the same variable:
a.init.add s.id
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar:
when trackGlobals:
a.addUse(copyNode(n))
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
if s.guard != nil: guardGlobal(a, n, s.guard)
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
tfGcSafe notin s.typ.flags:
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
a.gcUnsafe = true
type
@ -130,20 +223,27 @@ proc addToIntersection(inter: var TIntersection, s: int) =
proc throws(tracked, n: PNode) =
if n.typ == nil or n.typ.kind != tyError: tracked.add n
proc getEbase(): PType =
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
else: sysTypeFromName"E_Base"
proc excType(n: PNode): PType =
# reraise is like raising E_Base:
let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ
let t = if n.kind == nkEmpty: getEbase() else: n.typ
result = skipTypes(t, skipPtrs)
proc createRaise(n: PNode): PNode =
result = newNode(nkType)
result.typ = sysTypeFromName"E_Base"
result.typ = getEbase()
if not n.isNil: result.info = n.info
proc createTag(n: PNode): PNode =
result = newNode(nkType)
result.typ = sysTypeFromName"TEffect"
if getCompilerProc("RootEffect") != nil:
result.typ = sysTypeFromName"RootEffect"
else:
result.typ = sysTypeFromName"TEffect"
if not n.isNil: result.info = n.info
proc createAnyGlobal(n: PNode): PNode =
@ -179,17 +279,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) =
else:
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
when trackGlobals:
proc mergeUses(a: PEffects, b, comesFrom: PNode) =
if b.isNil:
addUse(a, createAnyGlobal(comesFrom))
else:
for effect in items(b): addUse(a, effect)
proc listEffects(a: PEffects) =
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
for e in items(a.uses): message(e.info, hintUser, e.sym.name.s)
#if a.maxLockLevel != 0:
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
proc catches(tracked: PEffects, e: PType) =
let e = skipTypes(e, skipPtrs)
@ -219,7 +313,9 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldState = tracked.init.len
var inter: TIntersection = @[]
track(tracked, n.sons[0])
inc tracked.inTryStmt
track(tracked, n.sons[0])
dec tracked.inTryStmt
for i in oldState.. <tracked.init.len:
addToIntersection(inter, tracked.init[i])
@ -274,7 +370,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
# list the computed effects up to here:
listEffects(tracked)
proc effectSpec(n: PNode, effectType = wRaises): PNode =
proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
@ -284,8 +380,7 @@ proc effectSpec(n: PNode, effectType = wRaises): PNode =
result.add(it.sons[1])
return
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
var x = x
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType)
if isNil(spec):
let s = n.sons[namePos].sym
@ -303,18 +398,20 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
# set the type so that the following analysis doesn't screw up:
effects.sons[i].typ = real[i].typ
var pair = newNode(nkExprColonExpr, n.info, @[
result = newNode(nkExprColonExpr, n.info, @[
newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
if x.kind == nkEmpty:
x = newNodeI(nkPragma, n.info)
n.sons[pragmasPos] = x
x.add(pair)
proc documentRaises*(n: PNode) =
if n.sons[namePos].kind != nkSym: return
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
let pragmas = n.sons[pragmasPos]
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
let p2 = documentEffect(n, pragmas, wTags, tagEffects)
if p1 != nil or p2 != nil:
if pragmas.kind == nkEmpty:
n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
if p1 != nil: n.sons[pragmasPos].add p1
if p2 != nil: n.sons[pragmasPos].add p2
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
@ -322,6 +419,25 @@ proc importedFromC(n: PNode): bool =
# when imported from C, we assume GC-safety.
result = n.kind == nkSym and sfImportc in n.sym.flags
proc getLockLevel(s: PSym): TLockLevel =
result = s.typ.lockLevel
if result == UnspecifiedLockLevel:
if {sfImportc, sfNoSideEffect} * s.flags != {} or
tfNoSideEffect in s.typ.flags:
result = 0.TLockLevel
else:
result = UnknownLockLevel
#message(s.info, warnUser, "FOR THIS " & s.name.s)
proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
if lockLevel >= tracked.currLockLevel:
# if in lock section:
if tracked.currLockLevel > 0.TLockLevel:
localError n.info, errGenerated,
"expected lock level < " & $tracked.currLockLevel &
" but got lock level " & $lockLevel
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
let pragma = s.ast.sons[pragmasPos]
let spec = effectSpec(pragma, wRaises)
@ -331,8 +447,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
mergeTags(tracked, tagSpec, n)
if notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
let n = n.skipConv
@ -352,8 +469,22 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
of impYes: discard
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
else: op.lockLevel
#if lockLevel == UnknownLockLevel:
# message(n.info, warnUser, "had to assume the worst here")
mergeLockLevels(tracked, n, lockLevel)
proc isOwnedProcVar(n: PNode; owner: PSym): bool =
# XXX prove the soundness of this effect system rule
result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
let op = skipConvAndClosure(n).typ
let a = skipConvAndClosure(n)
let op = a.typ
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
internalAssert op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
@ -365,21 +496,18 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
# we have no explicit effects but it's a forward declaration and so it's
# stated there are no additional effects, so simply propagate them:
propagateEffects(tracked, n, n.sym)
else:
elif not isOwnedProcVar(a, tracked.owner):
# we have no explicit effects so assume the worst:
addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
when trackGlobals: addUse(tracked, createAnyGlobal(n))
assumeTheWorst(tracked, n, op)
# assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op):
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
if notGcSafe(op):
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
notNilCheck(tracked, n, paramType)
@ -494,7 +622,8 @@ proc track(tracked: PEffects, n: PNode) =
useVar(tracked, n)
of nkRaiseStmt:
n.sons[0].info = n.info
throws(tracked.exc, n.sons[0])
#throws(tracked.exc, n.sons[0])
addEffect(tracked, n.sons[0], useLineInfo=false)
for i in 0 .. <safeLen(n):
track(tracked, n.sons[i])
of nkCallKinds:
@ -506,8 +635,12 @@ proc track(tracked: PEffects, n: PNode) =
# are indistinguishable from normal procs (both have tyProc type) and
# we can detect them only by checking for attached nkEffectList.
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
if a.kind == nkSym and a.sym == tracked.owner:
tracked.isRecursive = true
if a.kind == nkSym:
if a.sym == tracked.owner: tracked.isRecursive = true
# even for recursive calls we need to check the lock levels (!):
mergeLockLevels(tracked, n, a.sym.getLockLevel)
else:
mergeLockLevels(tracked, n, op.lockLevel)
var effectList = op.n.sons[0]
if a.kind == nkSym and a.sym.kind == skMethod:
propagateEffects(tracked, n, a.sym)
@ -515,18 +648,14 @@ proc track(tracked: PEffects, n: PNode) =
if isForwardedProc(a):
propagateEffects(tracked, n, a.sym)
elif isIndirectCall(a, tracked.owner):
addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
when trackGlobals: addUse(tracked, createAnyGlobal(n))
# XXX handle 'gcsafe' properly for callbacks!
assumeTheWorst(tracked, n, op)
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
if notGcSafe(op) and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
message(n.info, warnGcUnsafe, renderTree(n))
warnAboutGcUnsafe(n)
tracked.gcUnsafe = true
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
@ -534,6 +663,9 @@ proc track(tracked: PEffects, n: PNode) =
initVarViaNew(tracked, n.sons[1])
for i in 0 .. <safeLen(n):
track(tracked, n.sons[i])
of nkDotExpr:
guardDotAccess(tracked, n)
for i in 0 .. <len(n): track(tracked, n.sons[i])
of nkCheckedFieldExpr:
track(tracked, n.sons[0])
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
@ -541,19 +673,19 @@ proc track(tracked: PEffects, n: PNode) =
of nkPragma: trackPragmaStmt(tracked, n)
of nkAsgn, nkFastAsgn:
track(tracked, n.sons[1])
initVar(tracked, n.sons[0])
initVar(tracked, n.sons[0], volatileCheck=true)
invalidateFacts(tracked.guards, n.sons[0])
track(tracked, n.sons[0])
addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
notNilCheck(tracked, n.sons[1], n.sons[0].typ)
when false: cstringCheck(tracked, n)
of nkVarSection:
of nkVarSection, nkLetSection:
for child in n:
let last = lastSon(child)
if child.kind == nkIdentDefs and last.kind != nkEmpty:
track(tracked, last)
for i in 0 .. child.len-3:
initVar(tracked, child.sons[i])
initVar(tracked, child.sons[i], volatileCheck=false)
addAsgnFact(tracked.guards, child.sons[i], last)
notNilCheck(tracked, last, child.sons[i].typ)
# since 'var (a, b): T = ()' is not even allowed, there is always type
@ -589,6 +721,16 @@ proc track(tracked: PEffects, n: PNode) =
if sfDiscriminant in x.sons[0].sym.flags:
addDiscriminantFact(tracked.guards, x)
setLen(tracked.guards, oldFacts)
of nkPragmaBlock:
let pragmaList = n.sons[0]
let oldLocked = tracked.locked.len
let oldLockLevel = tracked.currLockLevel
for i in 0 .. <pragmaList.len:
if whichPragma(pragmaList.sons[i]) == wLocks:
lockLocations(tracked, pragmaList.sons[i])
track(tracked, n.lastSon)
setLen(tracked.locked, oldLocked)
tracked.currLockLevel = oldLockLevel
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef:
discard
@ -639,6 +781,16 @@ proc checkMethodEffects*(disp, branch: PSym) =
if sfThread in disp.flags and notGcSafe(branch.typ):
localError(branch.info, "base method is GC-safe, but '$1' is not" %
branch.name.s)
if branch.typ.lockLevel > disp.typ.lockLevel:
when true:
message(branch.info, warnLockLevel,
"base method has lock level $1, but dispatcher has $2" %
[$branch.typ.lockLevel, $disp.typ.lockLevel])
else:
# XXX make this an error after bigbreak has been released:
localError(branch.info,
"base method has lock level $1, but dispatcher has $2" %
[$branch.typ.lockLevel, $disp.typ.lockLevel])
proc setEffectsForProcType*(t: PType, n: PNode) =
var effects = t.n.sons[0]
@ -659,14 +811,13 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
effects.sons[usesEffects] = newNodeI(nkArgList, s.info)
t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects]
t.uses = effects.sons[usesEffects]
t.owner = s
t.init = @[]
t.guards = @[]
t.locked = @[]
proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0]
@ -700,9 +851,17 @@ proc trackProc*(s: PSym, body: PNode) =
if optThreadAnalysis in gGlobalOptions:
if sfThread in s.flags and t.gcUnsafe:
#localError(s.info, warnGcUnsafe2, s.name.s)
localError(s.info, "'$1' is not GC-safe" % s.name.s)
if optThreads in gGlobalOptions:
localError(s.info, "'$1' is not GC-safe" % s.name.s)
else:
localError(s.info, warnGcUnsafe2, s.name.s)
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
if s.typ.lockLevel == UnspecifiedLockLevel:
s.typ.lockLevel = t.maxLockLevel
elif t.maxLockLevel > s.typ.lockLevel:
localError(s.info,
"declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
@ -711,5 +870,5 @@ proc trackTopLevelStmt*(module: PSym; n: PNode) =
var effects = newNode(nkEffectList, n.info)
var t: TEffects
initEffects(effects, module, t)
t.isToplevel = true
track(t, n)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -29,17 +29,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
of nkIdent: s = lookUp(c, n.sons[0])
of nkSym: s = n.sons[0].sym
else: illFormedAst(n)
if s.kind == skLabel and s.owner.id == c.p.owner.id:
if s.kind == skLabel and s.owner.id == c.p.owner.id:
var x = newSymNode(s)
x.info = n.info
incl(s.flags, sfUsed)
n.sons[0] = x
suggestSym(x.info, s)
styleCheckUse(x.info, s)
else:
localError(n.info, errInvalidControlFlowX, s.name.s)
else:
localError(n.info, errGenerated, "'continue' cannot have a label")
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
localError(n.info, errInvalidControlFlowX,
renderTree(n, {renderNoComments}))
@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode =
var covered: BiggestInt = 0
var typ = commonTypeBegin
var hasElse = false
var notOrdinal = false
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
chckCovered = true
of tyFloat..tyFloat128, tyString, tyError:
discard
notOrdinal = true
else:
localError(n.info, errSelectorMustBeOfCertainTypes)
return
@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode =
hasElse = true
else:
illFormedAst(x)
if notOrdinal and not hasElse:
message(n.info, warnDeprecated,
"use 'else: discard'; non-ordinal case without 'else'")
if chckCovered:
if covered == toCover(n.sons[0].typ):
hasElse = true
@ -258,12 +263,13 @@ proc semTry(c: PContext, n: PNode): PNode =
n.sons[0] = semExprBranchScope(c, n.sons[0])
typ = commonType(typ, n.sons[0].typ)
var check = initIntSet()
for i in countup(1, sonsLen(n) - 1):
var last = sonsLen(n) - 1
for i in countup(1, last):
var a = n.sons[i]
checkMinSonsLen(a, 1)
var length = sonsLen(a)
if a.kind == nkExceptBranch:
# XXX what does this do? so that ``except [a, b, c]`` is supported?
# so that ``except [a, b, c]`` is supported:
if length == 2 and a.sons[0].kind == nkBracket:
a.sons[0..0] = a.sons[0].sons
length = a.sonsLen
@ -277,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode =
a.sons[j].typ = typ
if containsOrIncl(check, typ.id):
localError(a.sons[j].info, errExceptionAlreadyHandled)
elif a.kind != nkFinally:
elif a.kind != nkFinally:
illFormedAst(n)
# last child of an nkExcept/nkFinally branch is a statement:
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
typ = commonType(typ, a.sons[length-1].typ)
if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
else: dec last
dec c.p.inTryStmt
if isEmptyType(typ) or typ.kind == tyNil:
discardCheck(c, n.sons[0])
@ -289,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode =
if typ == enforceVoidContext:
result.typ = enforceVoidContext
else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
n.sons[0] = fitNode(c, typ, n.sons[0])
for i in 1..n.len-1:
for i in 1..last:
var it = n.sons[i]
let j = it.len-1
it.sons[j] = fitNode(c, typ, it.sons[j])
result.typ = typ
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
@ -323,6 +331,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
else:
result = semIdentWithPragma(c, kind, n, {})
suggestSym(n.info, result)
styleCheckDef(result)
proc checkNilable(v: PSym) =
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
@ -350,9 +359,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var def: PNode
if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
# BUGFIX: ``fitNode`` is needed here!
# check type compability between def.typ and typ:
if typ != nil: def = fitNode(c, typ, def)
if typ != nil:
if typ.isMetaType:
def = inferWithMetatype(c, typ, def)
typ = def.typ
else:
# BUGFIX: ``fitNode`` is needed here!
# check type compability between def.typ and typ
def = fitNode(c, typ, def)
#changeType(def.skipConv, typ, check=true)
else:
typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and
@ -441,7 +456,7 @@ proc semConst(c: PContext, n: PNode): PNode =
if typ == nil:
localError(a.sons[2].info, errConstExprExpected)
continue
if not typeAllowed(typ, skConst):
if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
localError(a.info, errXisNoType, typeToString(typ))
continue
v.typ = typ
@ -454,153 +469,7 @@ proc semConst(c: PContext, n: PNode): PNode =
addSon(b, copyTree(def))
addSon(result, b)
type
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
tupleType: PType # if != nil we're traversing a tuple
tupleIndex: int
field: PSym
replaceByFieldName: bool
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent:
result = n
var L = sonsLen(forLoop)
if c.replaceByFieldName:
if n.ident.id == forLoop[0].ident.id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
result = newStrNode(nkStrLit, fieldName)
return
# other fields:
for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, c.tupleIndex))
else:
result = newNodeI(nkDotExpr, n.info)
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1):
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
type
TFieldsCtx = object
c: PContext
m: TMagic
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
case typ.kind
of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(semStmt(c.c, body))
dec c.c.inUnrolledContext
closeScope(c.c)
of nkNilLit: discard
of nkRecCase:
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
localError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
semForObjectFields(c, typ[0], forLoop, father)
# we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
# generate selector:
var access = newNodeI(nkDotExpr, forLoop.info, 2)
access.sons[0] = call.sons[1]
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
caseStmt.add(semExprWithType(c.c, access))
# copy the branches over, but replace the fields with the for loop body:
for i in 1 .. <typ.len:
var branch = copyTree(typ[i])
let L = branch.len
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
caseStmt.add(branch)
father.add(caseStmt)
of nkRecList:
for t in items(typ): semForObjectFields(c, t, forLoop, father)
else:
illFormedAst(typ)
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
if trueSymbol == nil:
localError(n.info, errSystemNeeds, "true")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
trueSymbol.typ = getSysType(tyBool)
result.sons[0] = newSymNode(trueSymbol, n.info)
var stmts = newNodeI(nkStmtList, n.info)
result.sons[1] = stmts
var length = sonsLen(n)
var call = n.sons[length-2]
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
localError(n.info, errWrongNumberOfVariables)
return result
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1:
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
if not sameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
inc(c.p.nestedLoopCounter)
if tupleTypeA.kind == tyTuple:
var loopBody = n.sons[length-1]
for i in 0..sonsLen(tupleTypeA)-1:
openScope(c)
var fc: TFieldInstCtx
fc.tupleType = tupleTypeA
fc.tupleIndex = i
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.inUnrolledContext
stmts.add(semStmt(c, body))
dec c.inUnrolledContext
closeScope(c)
else:
var fc: TFieldsCtx
fc.m = m
fc.c = c
semForObjectFields(fc, tupleTypeA.n, n, stmts)
dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so
# we avoid it now if we can:
if hasSonWith(stmts, nkBreakStmt):
var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode)
stmts.add(b)
else:
result = stmts
include semfields
proc addForVarDecl(c: PContext, v: PSym) =
if warnShadowIdent in gNotes:
@ -614,6 +483,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
proc symForVar(c: PContext, n: PNode): PSym =
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
result = newSymG(skForVar, m, c)
styleCheckDef(result)
proc semForVars(c: PContext, n: PNode): PNode =
result = n
@ -906,7 +776,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
if it.kind == nkExprColonExpr:
# pass pragma argument to the macro too:
x.add(it.sons[1])
x.add(newProcNode(nkDo, prc.info, prc))
x.add(prc)
# recursion assures that this works for multiple macro annotations too:
return semStmt(c, x)
@ -934,6 +804,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
gp = newNodeI(nkGenericParams, n.info)
if n.sons[paramsPos].kind != nkEmpty:
#if n.kind == nkDo and not experimentalMode(c):
# localError(n.sons[paramsPos].info,
# "use the {.experimental.} pragma to enable 'do' with parameters")
semParamList(c, n.sons[paramsPos], gp, s)
# paramsTypeCheck(c, s.typ)
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
@ -1014,14 +887,21 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
proc semOverride(c: PContext, s: PSym, n: PNode) =
case s.name.s.normalize
of "destroy": doDestructorStuff(c, s, n)
of "destroy":
doDestructorStuff(c, s, n)
if not experimentalMode(c):
localError n.info, "use the {.experimental.} pragma to enable destructors"
of "deepcopy":
if s.typ.len == 2 and
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ.sons[1], s.typ.sons[0]):
# Note: we store the deepCopy in the base of the pointer to mitigate
# the problem that pointers are structural types:
let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
while true:
if t.kind == tyGenericBody: t = t.lastSon
elif t.kind == tyGenericInvokation: t = t.sons[0]
else: break
if t.kind in {tyObject, tyDistinct, tyEnum}:
if t.deepCopy.isNil: t.deepCopy = s
else:
@ -1036,6 +916,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
of "=": discard
else: localError(n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'")
incl(s.flags, sfUsed)
type
TProcCompilationSteps = enum
@ -1128,7 +1009,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pragma(c, s, n.sons[pragmasPos], validPragmas)
else:
implicitPragmas(c, s, n, validPragmas)
else:
else:
if n.sons[pragmasPos].kind != nkEmpty:
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
if sfForward notin proto.flags:
@ -1292,9 +1173,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
let pragmaList = n.sons[0]
pragma(c, nil, pragmaList, exprPragmas)
result = semExpr(c, n.sons[1])
n.sons[1] = result
for i in 0 .. <pragmaList.len:
if whichPragma(pragmaList.sons[i]) == wLine:
setLine(result, pragmaList.sons[i].info)
case whichPragma(pragmaList.sons[i])
of wLine: setLine(result, pragmaList.sons[i].info)
of wLocks:
result = n
result.typ = n.sons[1].typ
else: discard
proc semStaticStmt(c: PContext, n: PNode): PNode =
let a = semStmt(c, n.sons[0])
@ -1340,8 +1226,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# nkNilLit, nkEmpty}:
# dec last
for i in countup(0, length - 1):
case n.sons[i].kind
of nkFinally, nkExceptBranch:
let k = n.sons[i].kind
case k
of nkFinally, nkExceptBranch, nkDefer:
# stand-alone finally and except blocks are
# transformed into regular try blocks:
#
@ -1350,14 +1237,27 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# ... | ...
# | finally:
# | fclose(f)
var deferPart: PNode
if k == nkDefer:
deferPart = newNodeI(nkFinally, n.sons[i].info)
deferPart.add n.sons[i].sons[0]
elif k == nkFinally:
message(n.info, warnDeprecated,
"use 'defer'; standalone 'finally'")
deferPart = n.sons[i]
else:
message(n.info, warnDeprecated,
"use an explicit 'try'; standalone 'except'")
deferPart = n.sons[i]
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
var body = newNodeI(nkStmtList, n.sons[i].info)
if i < n.sonsLen - 1:
body.sons = n.sons[(i+1)..(-1)]
tryStmt.addSon(body)
tryStmt.addSon(n.sons[i])
tryStmt.addSon(deferPart)
n.sons[i] = semTry(c, tryStmt)
n.sons.setLen(i+1)
n.typ = n.sons[i].typ
return
else:
n.sons[i] = semExpr(c, n.sons[i])
@ -1393,11 +1293,16 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: discard
if result.len == 1:
result = result.sons[0]
when defined(nimfix):
if result.kind == nkCommentStmt and not result.comment.isNil and
not (result.comment[0] == '#' and result.comment[1] == '#'):
# it is an old-style comment statement: we replace it with 'discard ""':
prettybase.replaceComment(result.info)
when false:
# a statement list (s; e) has the type 'e':
if result.kind == nkStmtList and result.len > 0:
var lastStmt = lastSon(result)
if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt):
if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
result.typ = lastStmt.typ
#localError(lastStmt.info, errGenerated,
# "Last expression must be explicitly returned if it " &

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -63,7 +63,8 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
let kind = if r == scClosed: nkClosedSymChoice else: nkOpenSymChoice
let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
else: nkOpenSymChoice
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
@ -71,7 +72,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
addSon(result, newSymNode(a, n.info))
a = nextOverloadIter(o, c, n)
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
for i in 0 .. < n.len:
var a = n.sons[i]
# If 'a' is an overloaded symbol, we used to use the first symbol
@ -91,7 +92,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
illFormedAst(a)
result = newNodeI(nkEmpty, n.info)
proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode =
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
for i in 0 .. < n.len:
toMixin.incl(considerQuotedIdent(n.sons[i]).id)
result = newNodeI(nkEmpty, n.info)
@ -106,7 +107,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
type
TemplCtx {.pure, final.} = object
c: PContext
toBind, toMixin, toInject: TIntSet
toBind, toMixin, toInject: IntSet
owner: PSym
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
@ -146,6 +147,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else:
for i in 0 .. <n.safeLen:
result.sons[i] = onlyReplaceParams(c, n.sons[i])
@ -183,12 +185,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
if not isTemplParam(c, ident):
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
replaceIdentBySym(n, newSymNode(local, n.info))
else:
replaceIdentBySym(n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed)
# we do not call styleCheckUse here, as the identifier is not really
# resolved here. We will fixup the used identifiers later.
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
@ -204,7 +209,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
result = newSymNodeTypeDesc(s, n.info)
else:
result = n
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
result = n
@ -214,6 +220,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else:
for i in countup(0, safeLen(n) - 1):
result.sons[i] = semRoutineInTemplName(c, n.sons[i])
@ -228,6 +235,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(n.info, s)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
else:
n.sons[namePos] = ident
@ -261,6 +269,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
elif contains(c.toMixin, s.name.id):
@ -270,6 +279,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# var yz: T
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else:
result = semTemplSymbol(c.c, n, s)
of nkBind:
@ -322,6 +332,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# labels are always 'gensym'ed:
let s = newGenSym(skLabel, n.sons[0], c)
addPrelimDecl(c.c, s)
styleCheckDef(s)
n.sons[0] = newSymNode(s, n.sons[0].info)
n.sons[1] = semTemplBody(c, n.sons[1])
closeScope(c)
@ -456,6 +467,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
incl(s.flags, sfGlobal)
else:
s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(s)
# check parameter list:
s.scope = c.currentScope
pushOwner(s)
@ -527,6 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# semtypes.addParamOrResult). Within the pattern we have to ensure
# to use the param with the proper type though:
incl(s.flags, sfUsed)
styleCheckUse(n.info, s)
let x = c.owner.typ.n.sons[s.position+1].sym
assert x.name == s.name
result = newSymNode(x, n.info)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -82,6 +82,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
incl(e.flags, sfExported)
if not isPure: strTableAdd(c.module.tab, e)
addSon(result.n, newSymNode(e))
styleCheckDef(e)
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
inc(counter)
if not hasNull: incl(result.flags, tfNeedsInit)
@ -92,7 +93,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[1], nil)
addSonSkipIntLit(result, base)
if base.kind == tyGenericInst: base = lastSon(base)
if base.kind != tyGenericParam:
if base.kind != tyGenericParam:
if not isOrdinalType(base):
localError(n.info, errOrdinalTypeExpected)
elif lengthOrd(base) > MaxSetElements:
@ -169,9 +170,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
range[1] = semExprWithType(c, n[2], {efDetermineType})
var rangeT: array[2, PType]
for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
for i in 0..1:
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
if not sameType(rangeT[0], rangeT[1]):
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
localError(n.info, errPureTypeMismatch)
elif not rangeT[0].isOrdinalType:
localError(n.info, errOrdinalTypeExpected)
@ -279,9 +281,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if n.kind == nkSym:
result = n.sym
else:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
when defined(nimfix):
result = pickSym(c, n, skType)
if result.isNil:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
else:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if result != nil:
markUsed(n.info, result)
styleCheckUse(n.info, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound?
# it's not bound when it's used multiple times in the
@ -358,7 +366,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
else:
addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ)
if gCmd == cmdPretty: checkDef(a.sons[j], field)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
@ -378,13 +386,13 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
else:
result = newSymG(kind, n, c)
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
if n.kind == nkPragmaExpr:
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
if n.kind == nkPragmaExpr:
checkSonsLen(n, 2)
result = semIdentVis(c, kind, n.sons[0], allowed)
case kind
of skType:
of skType:
# process pragmas later, because result.typ has not been set yet
discard
of skField: pragma(c, result, n.sons[1], fieldPragmas)
@ -394,8 +402,8 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
if gCmd == cmdPretty: checkDef(n, result)
if gCmd == cmdPretty: styleCheckDef(n.info, result)
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
let ex = t[branchIndex][currentEx].skipConv
for i in countup(1, branchIndex):
@ -461,9 +469,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
swap(branch.sons[L-2], branch.sons[L-1])
checkForOverlap(c, t, i, branchIndex)
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
father: PNode, rectype: PType)
proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
father: PNode, rectype: PType) =
var a = copyNode(n)
checkMinSonsLen(n, 2)
@ -498,7 +506,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
localError(a.info, errNotAllCasesCovered)
addSon(father, a)
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
father: PNode, rectype: PType) =
if n == nil: return
case n.kind
@ -524,7 +532,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
else: illFormedAst(n)
if c.inGenericContext > 0:
# use a new check intset here for each branch:
var newCheck: TIntSet
var newCheck: IntSet
assign(newCheck, check)
var newPos = pos
var newf = newNodeI(nkRecList, n.info)
@ -574,11 +582,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
if a.kind == nkEmpty: addSon(father, newSymNode(f))
else: addSon(a, newSymNode(f))
styleCheckDef(f)
if a.kind != nkEmpty: addSon(father, a)
of nkEmpty: discard
else: illFormedAst(n)
proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
n: PNode) =
case n.kind
of nkRecCase:
@ -597,7 +606,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
inc(pos)
else: internalError(n.info, "addInheritedFieldsAux()")
proc addInheritedFields(c: PContext, check: var TIntSet, pos: var int,
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType) =
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
addInheritedFields(c, check, pos, obj.sons[0])
@ -814,10 +823,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
for i in 1 .. <paramType.sonsLen:
let lifted = liftingWalk(paramType.sons[i])
if lifted != nil: paramType.sons[i] = lifted
let expanded = instGenericContainer(c, info, paramType,
allowMetaTypes = true)
result = liftingWalk(expanded, true)
when false:
let expanded = instGenericContainer(c, info, paramType,
allowMetaTypes = true)
result = liftingWalk(expanded, true)
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
@ -828,6 +837,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
of tyGenericParam:
markUsed(info, paramType.sym)
styleCheckUse(info, paramType.sym)
if tfWildcard in paramType.flags:
paramType.flags.excl tfWildcard
paramType.sym.kind = skType
@ -844,10 +854,12 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
result = semTypeNode(c, n, nil)
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType, kind: TSymKind): PType =
prev: PType, kind: TSymKind; isType=false): PType =
# for historical reasons (code grows) this is invoked for parameter
# lists too and then 'isType' is false.
var
res: PNode
cl: TIntSet
cl: IntSet
checkMinSonsLen(n, 1)
result = newOrPrevType(tyProc, prev, c)
result.callConv = lastOptionEntry(c).defaultCC
@ -893,7 +905,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if not containsGenericType(typ):
def = fitNode(c, typ, def)
if not (hasType or hasDefault):
if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected")
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
typ = newTypeS(tdef, c)
@ -913,29 +926,32 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
addSon(result.n, newSymNode(arg))
rawAddSon(result, finalType)
addParamOrResult(c, arg, kind)
if gCmd == cmdPretty: checkDef(a.sons[j], arg)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
var r: PType
if n.sons[0].kind != nkEmpty:
r = semTypeNode(c, n.sons[0], nil)
elif kind == skIterator:
# XXX This is special magic we should likely get rid of
r = newTypeS(tyAnything, c)
if r != nil:
# turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil':
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
if r.sym == nil or sfAnon notin r.sym.flags:
let lifted = liftParamType(c, kind, genericParams, r, "result",
n.sons[0].info)
if lifted != nil: r = lifted
r.flags.incl tfRetType
r = skipIntLit(r)
if kind == skIterator:
# see tchainediterators
# in cases like iterator foo(it: iterator): type(it)
# we don't need to change the return type to iter[T]
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
# 'auto' as a return type does not imply a generic:
if r.kind != tyExpr:
if r.sym == nil or sfAnon notin r.sym.flags:
let lifted = liftParamType(c, kind, genericParams, r, "result",
n.sons[0].info)
if lifted != nil: r = lifted
r.flags.incl tfRetType
r = skipIntLit(r)
if kind == skIterator:
# see tchainediterators
# in cases like iterator foo(it: iterator): type(it)
# we don't need to change the return type to iter[T]
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
result.sons[0] = r
res.typ = r
@ -1059,7 +1075,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
prev: PType, kind: TSymKind): PType =
checkSonsLen(n, 2)
openScope(c)
result = semProcTypeNode(c, n.sons[0], nil, prev, kind)
result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
# dummy symbol for `pragma`:
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result
@ -1188,6 +1204,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
assignType(prev, t)
result = prev
markUsed(n.info, n.sym)
styleCheckUse(n.info, n.sym)
else:
if n.sym.kind != skError: localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
@ -1234,7 +1251,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
m.typ.kind = kind
m.typ.align = size
m.typ.align = size.int16
m.typ.size = size
proc processMagicType(c: PContext, m: PSym) =
@ -1332,6 +1349,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if def.typ.kind != tyTypeDesc:
typ = newTypeWithSons(c, tyStatic, @[def.typ])
else:
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
# from manyloc/named_argument_bug/triengine:
def.typ = def.typ.skipTypes({tyTypeDesc})
if not containsGenericType(def.typ):
def = fitNode(c, typ, def)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -216,7 +216,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
result.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return
@ -291,16 +291,24 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
var newbody = replaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags
newbody.callConv = body.callConv
result.flags = result.flags + newbody.flags - tfInstClearedFlags
# This is actually wrong: tgeneric_closure fails with this line:
#newbody.callConv = body.callConv
# This type may be a generic alias and we want to resolve it here.
# One step is enough, because the recursive nature of
# handleGenericInvokation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
let dc = newbody.deepCopy
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
# don't deal with '(): void':
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
t.sons[0] = nil

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -25,39 +25,17 @@ var
lastCaasCmd* = ""
# in caas mode, the list of defines and options will be given at start-up?
# it's enough to check that the previous compilation command is the same?
arguments* = ""
# the arguments to be passed to the program that
# should be run
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
while true:
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here
var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val
processSwitch(key, val, pass, gCmdLineInfo)
else:
processSwitch(p.key, p.val, pass, gCmdLineInfo)
of cmdEnd: break
of cmdLongoption, cmdShortOption: processSwitch(pass, p)
of cmdArgument:
if argsCount == 0:
options.command = p.key
else:
if pass == passCmd1: options.commandArgs.add p.key
if argsCount == 1:
# support UNIX style filenames anywhere for portable build scripts:
options.gProjectName = unixToNativePath(p.key)
arguments = cmdLineRest(p)
break
inc argsCount
if processArgument(pass, p, argsCount): break
if pass == passCmd2:
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
rawMessage(errArgsNeedRunOption, [])
@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) =
of "tcp", "":
when useCaas:
var server = socket()
if server == invalidSocket: osError(osLastError())
if server == invalidSocket: raiseOSError(osLastError())
let p = getConfigVar("server.port")
let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
let port = if p.len > 0: parseInt(p).Port else: 6000.Port
server.bindAddr(port, getConfigVar("server.address"))
var inp = "".TaintedString
server.listen()

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -12,7 +12,8 @@
import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
nimfix.pretty
when not defined(noDocgen):
import docgen
@ -21,7 +22,8 @@ type
TCandidateState* = enum
csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object
CandidateErrors* = seq[PSym]
TCandidate* = object
c*: PContext
exactMatches*: int # also misused to prefer iters over procs
genericMatches: int # also misused to prefer constraints
@ -44,7 +46,7 @@ type
# a distrinct type
typedescMatched: bool
inheritancePenalty: int # to prefer closest father object type
errors*: seq[string] # additional clarifications to be displayed to the
errors*: CandidateErrors # additional clarifications to be displayed to the
# user if overload resolution fails
TTypeRelation* = enum # order is important!
@ -201,16 +203,17 @@ proc writeMatches*(c: TCandidate) =
writeln(stdout, "intconv matches: " & $c.intConvMatches)
writeln(stdout, "generic matches: " & $c.genericMatches)
proc argTypeToString(arg: PNode): string =
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
if arg.kind in nkSymChoices:
result = typeToString(arg[0].typ)
result = typeToString(arg[0].typ, prefer)
for i in 1 .. <arg.len:
result.add(" | ")
result.add typeToString(arg[i].typ)
result.add typeToString(arg[i].typ, prefer)
else:
result = arg.typ.typeToString
result = arg.typ.typeToString(prefer)
proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
prefer: TPreferedDesc = preferName): string =
result = ""
for i in countup(startIdx, n.len - 1):
var arg = n.sons[i]
@ -226,7 +229,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
arg = c.semOperand(c, n.sons[i])
n.sons[i] = arg
if arg.typ.kind == tyError: return
add(result, argTypeToString(arg))
add(result, argTypeToString(arg, prefer))
if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
@ -239,6 +242,9 @@ proc concreteType(c: TCandidate, t: PType): PType =
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
of tyNil:
result = nil # what should it be?
of tySequence, tySet:
if t.sons[0].kind == tyEmpty: result = nil
else: result = t
of tyGenericParam, tyAnything:
result = t
while true:
@ -343,7 +349,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
var y = a.n.sons[i].sym
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
return isNone
if x.name.id != y.name.id: return isNone
if x.name.id != y.name.id and f.kind != tyTuple: return isNone
proc allowsNil(f: PType): TTypeRelation {.inline.} =
result = if tfNotNil notin f.flags: isSubtype else: isNone
@ -479,8 +485,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
dummyParam.typ = dummyType
addDecl(c, dummyParam)
var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false)
m.errors = bufferedMsgs
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
#m.errors = bufferedMsgs
clearBufferedMsgs()
if checkedBody == nil: return isNone
@ -930,6 +936,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
result = typeRel(c, f.lastSon, a)
if doBind and result notin {isNone, isGeneric}:
let concrete = concreteType(c, a)
if concrete == nil: return isNone
put(c.bindings, f, concrete)
else:
result = isGeneric
@ -1073,6 +1083,11 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode =
# arg.typ can be nil in 'suggest':
if isNil(arg.typ): return nil
# sem'checking for 'echo' needs to be re-entrant:
# XXX we will revisit this issue after 0.10.2 is released
if f == arg.typ and arg.kind == nkHiddenStdConv: return arg
var call = newNodeI(nkCall, arg.info)
call.add(f.n.copyTree)
call.add(arg.copyTree)
@ -1143,8 +1158,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
of isEqual: inc(m.exactMatches)
of isNone: discard
if f.kind == tyStmt and argOrig.kind == nkDo:
return argOrig[bodyPos]
if f.kind == tyStmt:
return arg
elif f.kind == tyTypeDesc:
return arg
elif f.kind == tyStatic:
@ -1272,6 +1287,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
else:
# only one valid interpretation found:
markUsed(arg.info, arg.sons[best].sym)
styleCheckUse(arg.info, arg.sons[best].sym)
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig)
@ -1319,7 +1335,7 @@ proc incrIndexType(t: PType) =
inc t.sons[0].n.sons[1].intVal
proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var TIntSet) =
m: var TCandidate, marker: var IntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} =
if not formal.constraint.isNil:
if matchNodeKinds(formal.constraint, n):
@ -1480,8 +1496,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
# instantiate generic converters for that
result = res != nil
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
procvar.} =
var m: TCandidate
initCandidate(c, m, dc.typ)
var f = dc.typ.sons[1]
if f.kind in {tyRef, tyPtr}: f = f.lastSon
if typeRel(m, f, t) == isNone:
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
else:
result = c.semGenerateInstance(c, dc, m.bindings, info)
assert sfFromGeneric in result.flags
include suggest
when not declared(tests):
template tests(s: stmt) {.immediate.} = discard
tests:
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -11,7 +11,7 @@
# included from sigmatch.nim
import algorithm, sequtils, pretty
import algorithm, sequtils
const
sep = '\t'
@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) =
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
suggestSym(info, s)
if gCmd == cmdPretty: checkUse(info, s)
proc useSym*(sym: PSym): PNode =
result = newSymNode(sym)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -44,7 +44,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
proc parseFile(fileIdx: int32): PNode =
var
p: TParsers
f: TFile
f: File
let filename = fileIdx.toFullPath
if not open(f, filename):
rawMessage(errCannotOpenFile, filename)

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -582,7 +582,7 @@ proc getMergeOp(n: PNode): PSym =
else: discard
proc flattenTreeAux(d, a: PNode, op: PSym) =
var op2 = getMergeOp(a)
let op2 = getMergeOp(a)
if op2 != nil and
(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)
@ -590,7 +590,7 @@ proc flattenTreeAux(d, a: PNode, op: PSym) =
addSon(d, copyTree(a))
proc flattenTree(root: PNode): PNode =
var op = getMergeOp(root)
let op = getMergeOp(root)
if op != nil:
result = copyNode(root)
addSon(result, copyTree(root.sons[0]))
@ -600,8 +600,9 @@ proc flattenTree(root: PNode): PNode =
proc transformCall(c: PTransf, n: PNode): PTransNode =
var n = flattenTree(n)
var op = getMergeOp(n)
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
let op = getMergeOp(n)
let magic = getMagic(n)
if op != nil and op.magic != mNone and n.len >= 3:
result = newTransNode(nkCall, n, 0)
add(result, transform(c, n.sons[0]))
var j = 1
@ -616,9 +617,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
inc(j)
add(result, a.PTransNode)
if len(result) == 2: result = result[1]
elif getMagic(n) == mNBindSym:
elif magic == mNBindSym:
# for bindSym(myconst) we MUST NOT perform constant folding:
result = n.PTransNode
elif magic == mProcCall:
# but do not change to its dispatcher:
result = transformSons(c, n[1])
else:
let s = transformSons(c, n).PNode
# bugfix: check after 'transformSons' if it's still a method call:
@ -785,8 +789,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
# result = lambdalifting.liftIterator(prc, result)
incl(result.flags, nfTransf)
when useEffectSystem: trackProc(prc, result)
if prc.name.s == "testbody":
echo renderTree(result)
#if prc.name.s == "testbody":
# echo renderTree(result)
proc transformStmt*(module: PSym, n: PNode): PNode =
if nfTransf in n.flags:

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
@ -117,7 +117,9 @@ proc isDeepConstExpr*(n: PNode): bool =
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false
result = true
# XXX once constant objects are supported by the codegen this needs to be
# weakened:
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
else: discard
proc flattenTreeAux(d, a: PNode, op: TMagic) =

View file

@ -1,6 +1,6 @@
#
#
# The Nimrod Compiler
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this

Some files were not shown because too many files have changed in this diff Show more