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

View file

@ -160,6 +160,7 @@ type
nkConstDef, # a const definition nkConstDef, # a const definition
nkTypeDef, # a type definition nkTypeDef, # a type definition
nkYieldStmt, # the yield statement as a tree nkYieldStmt, # the yield statement as a tree
nkDefer, # the 'defer' statement
nkTryStmt, # a try statement nkTryStmt, # a try statement
nkFinally, # a finally section nkFinally, # a finally section
nkRaiseStmt, # a raise statement nkRaiseStmt, # a raise statement
@ -293,6 +294,7 @@ const
# require RC ops # require RC ops
sfCompileToCpp* = sfInfixCall # compile the module as C++ code sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
const const
# getting ready for the future expr/stmt merge # getting ready for the future expr/stmt merge
@ -566,8 +568,8 @@ type
mBool, mChar, mString, mCstring, mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mIsMainModule, mCompileDate, mCompileTime, mProcCall,
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, mCpuEndian, mHostOS, mHostCPU, mAppType,
mNaN, mInf, mNegInf, mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg, mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
@ -610,7 +612,7 @@ const
# thus cannot be overloaded (also documented in the spec!): # thus cannot be overloaded (also documented in the spec!):
SpecialSemMagics* = { SpecialSemMagics* = {
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn} mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
type type
PNode* = ref TNode PNode* = ref TNode
@ -681,7 +683,6 @@ type
heapRoot*: PRope # keeps track of the enclosing heap object that heapRoot*: PRope # keeps track of the enclosing heap object that
# owns this location (required by GC algorithms # owns this location (required by GC algorithms
# employing heap snapshots or sliding views) # employing heap snapshots or sliding views)
a*: int
# ---------------- end of backend information ------------------------------ # ---------------- end of backend information ------------------------------
@ -734,7 +735,7 @@ type
# check for the owner when touching 'usedGenerics'. # check for the owner when touching 'usedGenerics'.
usedGenerics*: seq[PInstantiation] usedGenerics*: seq[PInstantiation]
tab*: TStrTable # interface table for modules tab*: TStrTable # interface table for modules
of skLet, skVar, skField: of skLet, skVar, skField, skForVar:
guard*: PSym guard*: PSym
else: nil else: nil
magic*: TMagic magic*: TMagic
@ -772,6 +773,7 @@ type
# it won't cause problems # it won't cause problems
TTypeSeq* = seq[PType] TTypeSeq* = seq[PType]
TLockLevel* = distinct int16
TType* {.acyclic.} = object of TIdObj # \ TType* {.acyclic.} = object of TIdObj # \
# types are identical iff they have the # types are identical iff they have the
# same id; there may be multiple copies of a type # same id; there may be multiple copies of a type
@ -798,11 +800,12 @@ type
deepCopy*: PSym # overriden 'deepCopy' operation deepCopy*: PSym # overriden 'deepCopy' operation
size*: BiggestInt # the size of the type in bytes size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown # -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 loc*: TLoc
TPair*{.final.} = object TPair*{.final.} = object
key*, val*: PObject key*, val*: RootRef
TPairSeq* = seq[TPair] TPairSeq* = seq[TPair]
TTable*{.final.} = object # the same as table[PObject] of PObject TTable*{.final.} = object # the same as table[PObject] of PObject
@ -811,7 +814,7 @@ type
TIdPair*{.final.} = object TIdPair*{.final.} = object
key*: PIdObj key*: PIdObj
val*: PObject val*: RootRef
TIdPairSeq* = seq[TIdPair] TIdPairSeq* = seq[TIdPair]
TIdTable*{.final.} = object # the same as table[PIdent] of PObject TIdTable*{.final.} = object # the same as table[PIdent] of PObject
@ -838,7 +841,7 @@ type
counter*: int counter*: int
data*: TNodePairSeq data*: TNodePairSeq
TObjectSeq* = seq[PObject] TObjectSeq* = seq[RootRef]
TObjectSet*{.final.} = object TObjectSet*{.final.} = object
counter*: int counter*: int
data*: TObjectSeq data*: TObjectSeq
@ -1054,7 +1057,7 @@ proc discardSons(father: PNode) =
father.sons = nil father.sons = nil
when defined(useNodeIds): when defined(useNodeIds):
const nodeIdToDebug* = 310841 # 612794 const nodeIdToDebug* = -1 # 884953 # 612794
#612840 # 612905 # 614635 # 614637 # 614641 #612840 # 612905 # 614635 # 614637 # 614641
# 423408 # 423408
#429107 # 430443 # 441048 # 441090 # 441153 #429107 # 430443 # 441048 # 441090 # 441153
@ -1166,6 +1169,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
result.sons = @[name, pattern, genericParams, params, result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body] 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 = proc newType(kind: TTypeKind, owner: PSym): PType =
new(result) new(result)
result.kind = kind result.kind = kind
@ -1173,6 +1186,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
result.size = - 1 result.size = - 1
result.align = 2 # default alignment result.align = 2 # default alignment
result.id = getID() result.id = getID()
result.lockLevel = UnspecifiedLockLevel
when debugIds: when debugIds:
registerId(result) registerId(result)
#if result.id < 2000: #if result.id < 2000:
@ -1184,7 +1198,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
a.flags = a.flags + b.flags a.flags = a.flags + b.flags
if a.t == nil: a.t = b.t if a.t == nil: a.t = b.t
if a.r == nil: a.r = b.r 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) = proc assignType(dest, src: PType) =
dest.kind = src.kind dest.kind = src.kind
@ -1195,6 +1209,7 @@ proc assignType(dest, src: PType) =
dest.align = src.align dest.align = src.align
dest.destructor = src.destructor dest.destructor = src.destructor
dest.deepCopy = src.deepCopy dest.deepCopy = src.deepCopy
dest.lockLevel = src.lockLevel
# this fixes 'type TLock = TSysLock': # this fixes 'type TLock = TSysLock':
if src.sym != nil: if src.sym != nil:
if dest.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: ## 'void' and 'stmt' types are often equivalent to 'nil' these days:
result = t == nil or t.kind in {tyEmpty, tyStmt} 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -14,7 +14,7 @@
import import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils 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 proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
# Convert a tree into its YAML representation; this is used by the # Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes. # 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 proc lineInfoToStr*(info: TLineInfo): PRope
# ----------------------- node sets: --------------------------------------- # ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: PObject): bool proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
# returns true whether n is in t # 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 # 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 ... # more are not needed ...
# ----------------------- (key, val)-Hashtables ---------------------------- # ----------------------- (key, val)-Hashtables ----------------------------
proc tablePut*(t: var TTable, key, val: PObject) proc tablePut*(t: var TTable, key, val: RootRef)
proc tableGet*(t: TTable, key: PObject): PObject proc tableGet*(t: TTable, key: RootRef): RootRef
type 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, proc tableSearch*(t: TTable, key, closure: RootRef,
comparator: TCmpProc): PObject comparator: TCmpProc): RootRef
# return val as soon as comparator returns true; if this never happens, # return val as soon as comparator returns true; if this never happens,
# nil is returned # nil is returned
@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.}
proc debug*(n: PNode) {.deprecated.} proc debug*(n: PNode) {.deprecated.}
# --------------------------- ident tables ---------------------------------- # --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): PObject proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
proc idTableGet*(t: TIdTable, key: int): PObject proc idTableGet*(t: TIdTable, key: int): RootRef
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject) proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only # checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id) # `key`'s id)
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
else: internalError(list.info, "getSymFromList") else: internalError(list.info, "getSymFromList")
result = nil result = nil
proc hashNode(p: PObject): THash = proc hashNode(p: RootRef): THash =
result = hash(cast[pointer](p)) result = hash(cast[pointer](p))
proc mustRehash(length, counter: int): bool = proc mustRehash(length, counter: int): bool =
@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope =
toRope(toLinenumber(info)), toRope(toLinenumber(info)),
toRope(toColumn(info))]) toRope(toColumn(info))])
proc treeToYamlAux(n: PNode, marker: var TIntSet, proc treeToYamlAux(n: PNode, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): PRope
proc symToYamlAux(n: PSym, marker: var TIntSet, proc symToYamlAux(n: PSym, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): PRope
proc typeToYamlAux(n: PType, marker: var TIntSet, proc typeToYamlAux(n: PType, marker: var IntSet,
indent, maxRecDepth: int): PRope 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 = maxRecDepth: int): PRope =
var istr = spaces(indent + 2) var istr = spaces(indent + 2)
result = toRope("[") result = toRope("[")
@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
inc(i, 2) inc(i, 2)
appf(result, "$N$1}", [spaces(indent)]) 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 = maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( 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: else:
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
result = ropeConstr(indent, [toRope("kind"), result = ropeConstr(indent, [toRope("kind"),
@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
flagsToStr(n.options), toRope("position"), flagsToStr(n.options), toRope("position"),
toRope(n.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 = maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( 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: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
result = toRope("[") result = toRope("[")
@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
toRope("align"), toRope(n.align), toRope("align"), toRope(n.align),
toRope("sons"), result]) toRope("sons"), result])
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
@ -450,9 +450,10 @@ proc debug(n: PSym) =
writeln(stdout, "skUnknown") writeln(stdout, "skUnknown")
else: else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [ writeln(stdout, "$1_$2: $3, $4, $5, $6" % [
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
flagsToStr(n.loc.flags), lineInfoToStr(n.info)]))) flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
$n.kind])
proc debug(n: PType) = proc debug(n: PType) =
writeln(stdout, ropeToStr(debugType(n))) 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 # generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof). # 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 # returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value var h: THash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil: while t.data[h] != nil:
@ -478,7 +479,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool =
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = false result = false
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) = proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
var h: THash = hashNode(obj) and high(data) var h: THash = hashNode(obj) and high(data)
while data[h] != nil: while data[h] != nil:
assert(data[h] != obj) assert(data[h] != obj)
@ -493,12 +494,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
if t.data[i] != nil: objectSetRawInsert(n, t.data[i]) if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n) 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) if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj) objectSetRawInsert(t.data, obj)
inc(t.counter) 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: # returns true if obj is already in the string table:
var h: THash = hashNode(obj) and high(t.data) var h: THash = hashNode(obj) and high(t.data)
while true: while true:
@ -516,7 +517,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
inc(t.counter) inc(t.counter)
result = false 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 var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
if t.data[h].key == key: if t.data[h].key == key:
@ -524,8 +525,8 @@ proc tableRawGet(t: TTable, key: PObject): int =
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = -1 result = -1
proc tableSearch(t: TTable, key, closure: PObject, proc tableSearch(t: TTable, key, closure: RootRef,
comparator: TCmpProc): PObject = comparator: TCmpProc): RootRef =
var h: THash = hashNode(key) and high(t.data) # start with real hash value var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
if t.data[h].key == key: if t.data[h].key == key:
@ -535,12 +536,12 @@ proc tableSearch(t: TTable, key, closure: PObject,
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = nil result = nil
proc tableGet(t: TTable, key: PObject): PObject = proc tableGet(t: TTable, key: RootRef): RootRef =
var index = tableRawGet(t, key) var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil 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) var h: THash = hashNode(key) and high(data)
while data[h].key != nil: while data[h].key != nil:
assert(data[h].key != key) 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) if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n) 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) var index = tableRawGet(t, key)
if index >= 0: if index >= 0:
t.data[index].val = val t.data[index].val = val
@ -626,20 +627,34 @@ proc strTableAdd(t: var TStrTable, n: PSym) =
strTableRawInsert(t.data, n) strTableRawInsert(t.data, n)
inc(t.counter) 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.} = proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
# returns true if n is already in the string table: # returns true if n is already in the string table:
# It is essential that `n` is written nevertheless! # It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses! # This way the newest redefinition is picked by the semantic analyses!
assert n.name != nil assert n.name != nil
var h: THash = n.name.h and high(t.data) var h: THash = n.name.h and high(t.data)
var replaceSlot = -1
while true: while true:
var it = t.data[h] var it = t.data[h]
if it == nil: break if it == nil: break
if it.name.id == n.name.id: # Semantic checking can happen multiple times thanks to templates
t.data[h] = n # overwrite it with newer definition! # and overloading: (var x=@[]; x).mapIt(it).
return true # found 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)) 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) strTableEnlarge(t)
strTableRawInsert(t.data, n) strTableRawInsert(t.data, n)
else: else:
@ -677,7 +692,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
ti.h = nextTry(h, high(tab.data)) ti.h = nextTry(h, high(tab.data))
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: TIntSet): PSym = excluding: IntSet): PSym =
var h: THash = ti.h and high(tab.data) var h: THash = ti.h and high(tab.data)
var start = h var start = h
result = tab.data[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 if result != nil and contains(excluding, result.id): result = nil
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: TIntSet): PSym = excluding: IntSet): PSym =
ti.h = s.h ti.h = s.h
ti.name = s ti.name = s
if tab.counter == 0: result = nil 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 if index >= 0: result = t.data[index].key == key
else: result = false else: result = false
proc idTableGet(t: TIdTable, key: PIdObj): PObject = proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id) var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil else: result = nil
proc idTableGet(t: TIdTable, key: int): PObject = proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key) var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil 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): for i in 0..high(t.data):
if t.data[i].key != nil: if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val) 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 var h: THash
h = key.id and high(data) h = key.id and high(data)
while data[h].key != nil: while data[h].key != nil:
@ -765,7 +780,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) = proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
var var
index: int index: int
n: TIdPairSeq n: TIdPairSeq
@ -784,7 +799,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
idTableRawInsert(t.data, key, val) idTableRawInsert(t.data, key, val)
inc(t.counter) 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): for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# this unit handles Nimrod sets; it implements bit sets # this unit handles Nim sets; it implements bit sets
# the code here should be reused in the Nimrod standard library # the code here should be reused in the Nim standard library
type type
TBitSet* = seq[int8] # we use byte here to avoid issues with 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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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: # the last entry of a symbol:
if s.ast != nil: if s.ast != nil:
# we used to attempt to save space here by only storing a dummy AST if # 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: # make that unfeasible nowadays:
encodeNode(w, s.info, s.ast, result) encodeNode(w, s.info, s.ast, result)

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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)]) result = ropef("$1, $1Len0", [rdLoc(a)])
of tyString, tySequence: of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar: 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: else:
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()]) result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]) result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: internalError("openArrayLoc: " & typeToString(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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -11,11 +11,19 @@
# -------------------------- constant expressions ------------------------ # -------------------------- 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 = proc intLiteral(i: BiggestInt): PRope =
if (i > low(int32)) and (i <= high(int32)): if i > low(int32) and i <= high(int32):
result = toRope(i) result = toRope(i)
elif i == low(int32): 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)" result = ~"(-2147483647 -1)"
elif i > low(int64): elif i > low(int64):
result = rfmt(nil, "IL64($1)", toRope(i)) result = rfmt(nil, "IL64($1)", toRope(i))
@ -31,7 +39,7 @@ proc int32Literal(i: int): PRope =
proc genHexLiteral(v: PNode): PRope = proc genHexLiteral(v: PNode): PRope =
# hex literals are unsigned in C # hex literals are unsigned in C
# so we don't generate hex literals any longer. # 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") internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal) result = intLiteral(v.intVal)
@ -46,16 +54,18 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
case skipTypes(ty, abstractVarRange).kind case skipTypes(ty, abstractVarRange).kind
of tyChar, tyInt64, tyNil: of tyChar, tyNil:
result = intLiteral(n.intVal) result = intLiteral(n.intVal)
of tyInt: 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)) result = int32Literal(int32(n.intVal))
else: else:
result = intLiteral(n.intVal) result = intLiteral(n.intVal)
of tyBool: of tyBool:
if n.intVal != 0: result = ~"NIM_TRUE" if n.intVal != 0: result = ~"NIM_TRUE"
else: result = ~"NIM_FALSE" else: result = ~"NIM_FALSE"
of tyInt64: result = int64Literal(n.intVal)
of tyUInt64: result = uint64Literal(uint64(n.intVal))
else: else:
result = ropef("(($1) $2)", [getTypeDesc(p.module, result = ropef("(($1) $2)", [getTypeDesc(p.module,
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]) 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) = proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let newflags = let newflags =
if src.k == locData: if src.k == locData:
flags + { needToCopy } flags + {needToCopy}
elif tfShallow in dest.t.flags: elif tfShallow in dest.t.flags:
flags - { needToCopy } flags - {needToCopy}
else: else:
flags flags
for i in 0 .. <dest.t.len: for i in 0 .. <dest.t.len:
@ -230,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
if t == nil: return if t == nil: return
let newflags = let newflags =
if src.k == locData: if src.k == locData:
flags + { needToCopy } flags + {needToCopy}
elif tfShallow in dest.t.flags: elif tfShallow in dest.t.flags:
flags - { needToCopy } flags - {needToCopy}
else: else:
flags flags
case t.kind 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)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyObject: of tyObject:
# XXX: check for subtyping? # 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: if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
discard getTypeDesc(p.module, ty) discard getTypeDesc(p.module, ty)
internalAssert ty.n != nil internalAssert ty.n != nil
@ -409,7 +421,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
d.k = locData d.k = locData
d.t = getUniqueType(t) d.t = getUniqueType(t)
d.r = r d.r = r
d.a = -1
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
var a: TLoc var a: TLoc
@ -425,7 +436,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
d.k = locExpr d.k = locExpr
d.t = getUniqueType(t) d.t = getUniqueType(t)
d.r = r d.r = r
d.a = -1
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc 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), ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)])) getSimpleTypeDesc(p.module, e.typ)]))
proc genDeref(p: BProc, e: PNode, d: var TLoc) = proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
var a: TLoc let mt = mapType(e.sons[0].typ)
if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}: if mt in {ctArray, ctPtrToArray} and not enforceDeref:
# XXX the amount of hacks for C's arrays is incredible, maybe we should # XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then? # 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) expr(p, e.sons[0], d)
else: else:
var a: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
case skipTypes(a.t, abstractInst).kind case skipTypes(a.t, abstractInst).kind
of tyRef: of tyRef:
@ -663,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
of tyPtr: of tyPtr:
d.s = OnUnknown # BUGFIX! d.s = OnUnknown # BUGFIX!
else: internalError(e.info, "genDeref " & $a.t.kind) 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) = proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand: # 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") internalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name) field = lookupInRecord(ty.n, f.name)
if field != nil: break if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup") if not p.module.compileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genRecordField 2 ") if field == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3") 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}) assert(ty.kind in {tyTuple, tyObject})
field = lookupInRecord(ty.n, f.name) field = lookupInRecord(ty.n, f.name)
if field != nil: break if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup") if not p.module.compileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genCheckedRecordField") if field == nil: internalError(e.info, "genCheckedRecordField")
if field.loc.r == nil: if field.loc.r == nil:
@ -786,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
else: else:
genRecordField(p, e.sons[0], d) 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 var a, b: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, x, a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, y, b)
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs) var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
var first = intLiteral(firstOrd(ty)) var first = intLiteral(firstOrd(ty))
# emit range check: # emit range check:
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags: 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 # semantic pass has already checked for const index expressions
if firstOrd(ty) == 0: if firstOrd(ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)): 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", linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
rdCharLoc(b), first, intLiteral(lastOrd(ty))) rdCharLoc(b), first, intLiteral(lastOrd(ty)))
else: else:
let idx = getOrdValue(e.sons[1]) let idx = getOrdValue(y)
if idx < firstOrd(ty) or idx > lastOrd(ty): if idx < firstOrd(ty) or idx > lastOrd(ty):
localError(e.info, errIndexOutOfBounds) localError(x.info, errIndexOutOfBounds)
d.inheritLocation(a) d.inheritLocation(a)
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first)) 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 var a, b: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, x, a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange) var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) 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 var a, b: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, x, a)
initLocExpr(p, e.sons[1], b) # emit range check: initLocExpr(p, y, b) # emit range check:
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n", linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! 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)), putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) 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 var a, b: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, x, a)
initLocExpr(p, e.sons[1], b) initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange) var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: 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: if ty.kind == tyString:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField()) rdLoc(b), rdLoc(a), lenField(p))
else: else:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", "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 if d.k == locNone: d.s = OnHeap
d.heapRoot = a.r d.heapRoot = a.r
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: 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)), putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b))) 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) = proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# how to generate code? # how to generate code?
# 'expr1 and expr2' becomes: # '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) = proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe. # is threadsafe.
internalAssert n.kind == nkBracket
discard lists.includeStr(p.module.headerFiles, "<stdio.h>") discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
var args: PRope = nil var args: PRope = nil
var a: TLoc 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) initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)]) appf(args, ", ($1)->data", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n", 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) = proc gcUsage(n: PNode) =
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code> # <Nim code>
# s = 'Hello ' & name & ', how do you feel?' & 'z' # s = 'Hello ' & name & ', how do you feel?' & 'z'
# #
# <generated C code> # <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}: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal)) inc(L, len(e.sons[i + 1].strVal))
else: 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))) 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)) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
app(p.s(cpsStmts), appends) app(p.s(cpsStmts), appends)
@ -951,7 +984,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
gcUsage(e) gcUsage(e)
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code> # <Nim code>
# s &= 'Hello ' & name & ', how do you feel?' & 'z' # s &= 'Hello ' & name & ', how do you feel?' & 'z'
# // BUG: what if s is on the left side too? # // BUG: what if s is on the left side too?
# <generated C code> # <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}: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal)) inc(L, len(e.sons[i + 2].strVal))
else: 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", app(appends, rfmt(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a))) rdLoc(dest), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", 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 &= x -->
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = 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" "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else: else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n" "$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))]) getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
keepAlive(p, a) keepAlive(p, a)
initLoc(dest, locExpr, b.t, OnHeap) 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}) genAssignment(p, dest, b, {needToCopy, afDestIsNil})
gcUsage(e) gcUsage(e)
@ -1099,11 +1132,11 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
while ty != nil: while ty != nil:
field = lookupInRecord(ty.n, it.sons[0].sym.name) field = lookupInRecord(ty.n, it.sons[0].sym.name)
if field != nil: break 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]) ty = getUniqueType(ty.sons[0])
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr") if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options: 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, ".")
app(tmp2.r, field.loc.r) app(tmp2.r, field.loc.r)
tmp2.k = locTemp tmp2.k = locTemp
@ -1200,8 +1233,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
if t.kind != tyVar: nilCheck = r if t.kind != tyVar: nilCheck = r
r = rfmt(nil, "(*$1)", r) r = rfmt(nil, "(*$1)", r)
t = skipTypes(t.lastSon, typedescInst) t = skipTypes(t.lastSon, typedescInst)
if gCmd != cmdCompileToCpp: if not p.module.compileToCpp:
while (t.kind == tyObject) and (t.sons[0] != nil): while t.kind == tyObject and t.sons[0] != nil:
app(r, ~".Sup") app(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst) t = skipTypes(t.sons[0], typedescInst)
if isObjLackingTypeField(t): 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)])) putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
of tyString, tySequence: of tyString, tySequence:
putIntoDest(p, b, e.typ, 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: of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ, putIntoDest(p, b, e.typ,
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])) 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)") if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
else: unaryExpr(p, e, d, "strlen($1)") else: unaryExpr(p, e, d, "strlen($1)")
of tyString, tySequence: of tyString, tySequence:
if gCmd != cmdCompileToCpp: if not p.module.compileToCpp:
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)") if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
else: unaryExpr(p, e, d, "$1->Sup.len") else: unaryExpr(p, e, d, "$1->Sup.len")
else: else:
@ -1307,7 +1340,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar) 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" "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
else: else:
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n" "$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", linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl) getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
tmp.k = locExpr tmp.k = locExpr
tmp.a = -1
tmp.t = srct tmp.t = srct
tmp.s = OnStack tmp.s = OnStack
tmp.flags = {} tmp.flags = {}
@ -1564,11 +1596,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
initLocExpr(p, e.sons[2], x) initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e.typ, 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 == ""): elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
initLocExpr(p, e.sons[1], x) initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e.typ, 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: else:
binaryExpr(p, e, d, "#eqStrings($1, $2)") 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) discard cgsym(p.module, opr.loc.r.ropeToStr)
genCall(p, e, d) genCall(p, e, d)
of mReset: genReset(p, e) of mReset: genReset(p, e)
of mEcho: genEcho(p, e) of mEcho: genEcho(p, e[1].skipConv)
of mArrToSeq: genArrToSeq(p, e, d) of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError: of mNLen..mNError:
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s) 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 genConstExpr(p: BProc, n: PNode): PRope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = 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) var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) 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 if t.kind != tyVar: nilCheck = r
r = ropef("(*$1)", [r]) r = ropef("(*$1)", [r])
t = skipTypes(t.lastSon, abstractInst) t = skipTypes(t.lastSon, abstractInst)
if gCmd != cmdCompileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
app(r, ".Sup") app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst) 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)])) [getTypeDesc(p.module, dest), addrLoc(a)]))
proc downConv(p: BProc, n: PNode, d: var TLoc) = 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 expr(p, n.sons[0], d) # downcast does C++ for us
else: else:
var dest = skipTypes(n.typ, abstractPtrs) 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 var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, arg, a)
var r = rdLoc(a) var r = rdLoc(a)
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}: if isRef:
app(r, "->Sup") app(r, "->Sup")
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
r = con("&", r)
else: else:
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup") app(r, ".Sup")
putIntoDest(p, d, n.typ, r) 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) = proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ) 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 nkCast: genCast(p, n, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
of nkHiddenAddr, nkAddr: genAddr(p, n, d) of nkHiddenAddr, nkAddr: genAddr(p, n, d)
of nkBracketExpr: of nkBracketExpr: genBracketExpr(p, n, d)
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 nkDerefExpr, nkHiddenDeref: genDeref(p, n, d) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d) of nkDotExpr: genRecordField(p, n, d)
of nkCheckedFieldExpr: genCheckedRecordField(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) initLocExpr(p, n.sons[0], a)
of nkAsmStmt: genAsmStmt(p, n) of nkAsmStmt: genAsmStmt(p, n)
of nkTryStmt: of nkTryStmt:
if gCmd == cmdCompileToCpp: genTryCpp(p, n, d) if p.module.compileToCpp: genTryCpp(p, n, d)
else: genTry(p, n, d) else: genTry(p, n, d)
of nkRaiseStmt: genRaiseStmt(p, n) of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection: of nkTypeSection:
@ -2043,6 +2082,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
nkFromStmt, nkTemplateDef, nkMacroDef: nkFromStmt, nkTemplateDef, nkMacroDef:
discard discard
of nkPragma: genPragma(p, n) of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d)
of nkProcDef, nkMethodDef, nkConverterDef: of nkProcDef, nkMethodDef, nkConverterDef:
if (n.sons[genericParamsPos].kind == nkEmpty): if (n.sons[genericParamsPos].kind == nkEmpty):
var prc = n.sons[namePos].sym var prc = n.sons[namePos].sym

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) =
if useLowering: if useLowering:
genStmts(p, lowerTupleUnpacking(n, p.prc)) genStmts(p, lowerTupleUnpacking(n, p.prc))
return return
genLineDir(p, n) genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup) initLocExpr(p, n.sons[L-1], tup)
var t = tup.t var t = tup.t
@ -69,10 +68,21 @@ proc genVarTuple(p: BProc, n: PNode) =
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]) [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field) 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.} = proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
ri.sons[0].sym.magic == mNone): ri.sons[0].sym.magic == mNone):
genAsgnCall(p, le, ri, a) 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: else:
expr(p, ri, a) expr(p, ri, a)
@ -294,8 +304,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
var alreadyPoppedCnt = p.inExceptBlock var alreadyPoppedCnt = p.inExceptBlock
for i in countup(1, howManyTrys): for i in countup(1, howManyTrys):
if not p.module.compileToCpp:
if gCmd != cmdCompileToCpp:
# Pop safe points generated by try # Pop safe points generated by try
if alreadyPoppedCnt > 0: if alreadyPoppedCnt > 0:
dec alreadyPoppedCnt dec alreadyPoppedCnt
@ -317,7 +326,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
for i in countdown(howManyTrys-1, 0): for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i]) p.nestedTryStmts.add(stack[i])
if gCmd != cmdCompileToCpp: if not p.module.compileToCpp:
# Pop exceptions that was handled by the # Pop exceptions that was handled by the
# except-blocks we are in # except-blocks we are in
for i in countdown(howManyExcepts-1, 0): 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) assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym var sym = t.sons[0].sym
sym.loc.k = locOther sym.loc.k = locOther
sym.loc.a = p.breakIdx sym.position = p.breakIdx+1
expr(p, t.sons[1], d) expr(p, t.sons[1], d)
endBlock(p) endBlock(p)
@ -487,7 +496,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
assert(t.sons[0].kind == nkSym) assert(t.sons[0].kind == nkSym)
var sym = t.sons[0].sym var sym = t.sons[0].sym
assert(sym.loc.k == locOther) assert(sym.loc.k == locOther)
idx = sym.loc.a idx = sym.position-1
else: else:
# an unnamed 'break' can only break a loop after 'transf' pass: # an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx 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]) lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string = proc getRaiseFrmt(p: BProc): string =
if gCmd == cmdCompileToCpp: if p.module.compileToCpp:
result = "throw NimException($1, $2);$n" result = "throw NimException($1, $2);$n"
elif getCompilerProc("Exception") != nil:
result = "#raiseException((#Exception*)$1, $2);$n"
else: else:
result = "#raiseException((#E_Base*)$1, $2);$n" 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) var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t) genLineDir(p, t)
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
else: else:
genLineDir(p, t) genLineDir(p, t)
# reraise the last exception: # reraise the last exception:
if gCmd == cmdCompileToCpp: if p.module.compileToCpp:
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, ~"throw;$n")
else: else:
linefmt(p, cpsStmts, "#reraiseException();$n") 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, proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr, rangeFormat, eqFormat: TFormatStr,
until: int, a: TLoc): TLabel = 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 var labId = p.labels
for i in 1..until: for i in 1..until:
inc(p.labels) inc(p.labels)
@ -747,7 +758,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
i, length, blen: int i, length, blen: int
genLineDir(p, t) genLineDir(p, t)
exc = getTempName() 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) add(p.nestedTryStmts, t)
startBlock(p, "try {$n") startBlock(p, "try {$n")
expr(p, t.sons[0], d) expr(p, t.sons[0], d)
@ -784,7 +798,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
startBlock(p) startBlock(p)
var finallyBlock = t.lastSon var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally: 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") line(p, cpsStmts, ~"throw;$n")
endBlock(p) endBlock(p)
@ -793,7 +809,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.nestedTryStmts) discard pop(p.nestedTryStmts)
if (i < length) and (t.sons[i].kind == nkFinally): 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) = proc genTry(p: BProc, t: PNode, d: var TLoc) =
# code to generate: # code to generate:
@ -829,7 +845,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>") discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t) genLineDir(p, t)
var safePoint = getTempName() 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, cpsLocals, "#TSafePoint $1;$n", safePoint)
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
if isDefined("nimStdSetjmp"): if isDefined("nimStdSetjmp"):
@ -882,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
endBlock(p) # end of else block endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally: if i < length and t.sons[i].kind == nkFinally:
p.finallySafePoints.add(safePoint) p.finallySafePoints.add(safePoint)
exprBlock(p, t.sons[i].sons[0], d) genSimpleBlock(p, t.sons[i].sons[0])
discard pop(p.finallySafePoints) discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -57,6 +57,9 @@ proc generateThreadLocalStorage(m: BModule) =
proc generateThreadVarsSize(m: BModule) = proc generateThreadVarsSize(m: BModule) =
if nimtv != nil: if nimtv != nil:
app(m.s[cfsProcs], let externc = if gCmd != cmdCompileToCpp and
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl) 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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) genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
else: internalError(n.info, "genTraverseProc()") else: internalError(n.info, "genTraverseProc()")
proc parentObj(accessor: PRope): PRope {.inline.} = proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
if gCmd != cmdCompileToCpp: if not m.compileToCpp:
result = ropef("$1.Sup", accessor) result = ropef("$1.Sup", accessor)
else: else:
result = accessor result = accessor
@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
lineF(p, cpsStmts, "}$n") lineF(p, cpsStmts, "}$n")
of tyObject: of tyObject:
for i in countup(0, sonsLen(typ) - 1): 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) if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple: of tyTuple:
let typ = getUniqueType(typ) let typ = getUniqueType(typ)
@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", 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]) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
lineF(p, cpsStmts, "}$n") lineF(p, cpsStmts, "}$n")

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -62,7 +62,7 @@ type
frameLen*: int16 frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated 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 beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar threadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are nestedTryStmts*: seq[PNode] # in how many nested try statements we are
@ -101,10 +101,10 @@ type
# without extension) # without extension)
typeCache*: TIdTable # cache the generated types typeCache*: TIdTable # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types forwTypeCache*: TIdTable # cache for forward declarations of types
declaredThings*: TIntSet # things we have declared in this .c file declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: TIntSet # prototypes we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: TLinkedList # needed headers to include 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 initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -155,7 +155,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
if not sameType(t2, t): if not sameType(t2, t):
return true 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): for col in countup(1, sonsLen(a.typ) - 1):
if contains(relevantCols, col): if contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs) var aa = skipTypes(a.typ.sons[col], skipPtrs)
@ -164,7 +164,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
if (d != high(int)): if (d != high(int)):
return d return d
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) = proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
# we use shellsort here; fast and simple # we use shellsort here; fast and simple
var n = len(a) var n = len(a)
var h = 1 var h = 1
@ -183,7 +183,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
a[j] = v a[j] = v
if h == 1: break 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 var base = lastSon(methods[0].ast).sym
result = base result = base
var paramLen = sonsLen(base.typ) var paramLen = sonsLen(base.typ)

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import import
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, 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. # but some have deps to imported modules. Yay.
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
@ -43,7 +43,7 @@ type
TCmdLinePass* = enum TCmdLinePass* = enum
passCmd1, # first pass over the command line passCmd1, # first pass over the command line
passCmd2, # second 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 processCommand*(switch: string, pass: TCmdLinePass)
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
# implementation # implementation
const 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" "Copyright (c) 2006-2014 by Andreas Rumpf\n"
const const
@ -226,6 +226,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
of "implicitstatic": result = contains(gOptions, optImplicitStatic) of "implicitstatic": result = contains(gOptions, optImplicitStatic)
of "patterns": result = contains(gOptions, optPatterns) of "patterns": result = contains(gOptions, optPatterns)
of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info) else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false): string = proc processPath(path: string, notRelativeToProj = false): string =
@ -234,7 +235,9 @@ proc processPath(path: string, notRelativeToProj = false): string =
path path
else: else:
options.gProjectPath / path options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath, result = unixToNativePath(p % ["nimrod", getPrefixDir(),
"nim", getPrefixDir(),
"lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir()), "home", removeTrailingDirSep(os.getHomeDir()),
"projectname", options.gProjectName, "projectname", options.gProjectName,
"projectpath", options.gProjectPath]) "projectpath", options.gProjectPath])
@ -280,14 +283,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "path", "p": of "path", "p":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
addPath(processPath(arg), info) addPath(processPath(arg), info)
of "babelpath": of "nimblepath", "babelpath":
if pass in {passCmd2, passPP} and not options.gNoBabelPath: # keep the old name for compat
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
let path = processPath(arg, notRelativeToProj=true) let path = processPath(arg, notRelativeToProj=true)
babelpath(path, info) nimblePath(path, info)
of "nobabelpath": of "nonimblepath", "nobabelpath":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
options.gNoBabelPath = true options.gNoNimblePath = true
of "excludepath": of "excludepath":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
let path = processPath(arg) let path = processPath(arg)
@ -307,8 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.docSeeSrcUrl = arg options.docSeeSrcUrl = arg
of "mainmodule", "m": of "mainmodule", "m":
expectArg(switch, arg, pass, info) discard "allow for backwards compatibility, but don't do anything"
optMainModule = arg
of "define", "d": of "define", "d":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
defineSymbol(arg) defineSymbol(arg)
@ -566,6 +569,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "none": idents.firstCharIsCS = false of "none": idents.firstCharIsCS = false
else: localError(info, errGenerated, else: localError(info, errGenerated,
"'partial' or 'none' expected, but found " & arg) "'partial' or 'none' expected, but found " & arg)
of "experimental":
expectNoArg(switch, arg, pass, info)
gExperimentalMode = true
else: else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info) else: invalidCmdLineOption(pass, switch, info)
@ -574,3 +580,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(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 # We need to use a PStringTable here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose. # to be style insensitive. Otherwise hell would break lose.
var gSymbols: PStringTable var gSymbols: StringTableRef
proc defineSymbol*(symbol: string) = proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true" gSymbols[symbol] = "true"
@ -41,12 +41,12 @@ proc countDefinedSymbols*(): int =
for key, val in pairs(gSymbols): for key, val in pairs(gSymbols):
if val == "true": inc(result) 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: # file for now:
const const
additionalSymbols = """ additionalSymbols = """
x86 itanium x8664 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 mac
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9 hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
@ -88,6 +88,7 @@ proc initDefines*() =
defineSymbol("nimrequiresnimframe") defineSymbol("nimrequiresnimframe")
defineSymbol("nimparsebiggestfloatmagic") defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias") defineSymbol("nimalias")
defineSymbol("nimlocks")
# add platform specific symbols: # add platform specific symbols:
for c in low(CPU)..high(CPU): for c in low(CPU)..high(CPU):

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 =
const const
bufSize = 8000 # don't use 8K for the memory allocator! bufSize = 8000 # don't use 8K for the memory allocator!
var var
bin: TFile bin: File
result = InitCrc32 result = InitCrc32
if not open(bin, filename): if not open(bin, filename):
return # not equal if file does not exist 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -23,7 +23,7 @@ type
id: int # for generating IDs id: int # for generating IDs
toc, section: TSections toc, section: TSections
indexValFilename: string 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. PDoc* = ref TDocumentor ## Alias to type less.
@ -41,6 +41,7 @@ proc compilerMsgHandler(filename: string, line, col: int,
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported of mwUnsupportedLanguage: k = warnLanguageXNotSupported
of mwUnsupportedField: k = warnFieldXNotSupported
globalError(newLineInfo(filename, line, col), k, arg) globalError(newLineInfo(filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} = proc docgenFindFile(s: string): string {.procvar.} =
@ -55,7 +56,7 @@ proc parseRst(text, filename: string,
result = rstParse(text, filename, line, column, hasToc, rstOptions, result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler) docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, config: PStringTable): PDoc = proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
new(result) new(result)
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
options.gConfigVars, filename, {roSupportRawDirective}, options.gConfigVars, filename, {roSupportRawDirective},
@ -374,11 +375,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
cleanPlainSymbol = renderPlainSymbolName(nameNode) cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol) complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol) plainSymbolRope = toRope(cleanPlainSymbol)
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol)) plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
itemIDRope = toRope(d.id) itemIDRope = toRope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope symbolOrIdRope = symbolOrId.toRope
symbolOrIdEncRope = URLEncode(symbolOrId).toRope symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
var seeSrcRope: PRope = nil var seeSrcRope: PRope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc") let docItemSeeSrc = getConfigVar("doc.item.seesrc")
@ -413,7 +414,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
setIndexTerm(d[], symbolOrId, name, linkTitle, setIndexTerm(d[], symbolOrId, name, linkTitle,
xmltree.escape(plainDocstring.docstringSummary)) 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 if not isVisible(nameNode): return
var var
name = getName(d, nameNode) name = getName(d, nameNode)
@ -473,7 +474,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
else: discard 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 case n.kind
of nkCommentStmt: of nkCommentStmt:
if n.comment != nil and startsWith(n.comment, "##"): 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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) writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
try: try:
generateIndex(g.doc) generateIndex(g.doc)
except EIO: except IOError:
discard discard
proc processNode(c: PPassContext, n: PNode): PNode = proc processNode(c: PPassContext, n: PNode): PNode =

View file

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

View file

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

View file

@ -1,13 +1,13 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module implements Nimrod's simple filters and helpers for filters. # This module implements Nim's simple filters and helpers for filters.
import import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, 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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) =
fact.sons[2] = value fact.sons[2] = value
m.add fact 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) = proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
let branch = n.sons[i] let branch = n.sons[i]
if branch.kind == nkOfBranch: if branch.kind == nkOfBranch:

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,13 +1,13 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## 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 import parseutils, strutils, strtabs, os, options, msgs, lists
@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool =
if a[i] == '.': inc i if a[i] == '.': inc i
if b[j] == '.': inc j if b[j] == '.': inc j
proc addPackage(packages: PStringTable, p: string) = proc addPackage(packages: StringTableRef, p: string) =
let x = versionSplitPos(p) let x = versionSplitPos(p)
let name = p.substr(0, x-1) let name = p.substr(0, x-1)
if x < p.len: if x < p.len:
@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) =
else: else:
packages[name] = latest packages[name] = latest
iterator chosen(packages: PStringTable): string = iterator chosen(packages: StringTableRef): string =
for key, val in pairs(packages): for key, val in pairs(packages):
let res = if val == latest: key else: key & '-' & val let res = if val == latest: key else: key & '-' & val
yield res yield res
proc addBabelPath(p: string, info: TLineInfo) = proc addNimblePath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p): if not contains(options.searchPaths, p):
if gVerbosity >= 1: message(info, hintPath, p) if gVerbosity >= 1: message(info, hintPath, p)
lists.prependStr(options.lazyPaths, p) lists.prependStr(options.lazyPaths, p)
@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) =
result = true result = true
break break
if hasNimFile(p): if hasNimFile(p):
addBabelPath(p, info) addNimblePath(p, info)
else: else:
for kind, p2 in walkDir(p): for kind, p2 in walkDir(p):
if hasNimFile(p2): addBabelPath(p2, info) if hasNimFile(p2): addNimblePath(p2, info)
proc addPathRec(dir: string, info: TLineInfo) = proc addPathRec(dir: string, info: TLineInfo) =
var packages = newStringTable(modeStyleInsensitive) var packages = newStringTable(modeStyleInsensitive)
@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) =
if k == pcDir and p[pos] != '.': if k == pcDir and p[pos] != '.':
addPackage(packages, p) addPackage(packages, p)
for p in packages.chosen: 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) 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -14,7 +14,7 @@ import
options, idents, wordrecg options, idents, wordrecg
# ---------------- configuration file parser ----------------------------- # ---------------- 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) = proc ppGetTok(L: var TLexer, tok: var TToken) =
# simple filter # simple filter
@ -113,7 +113,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
case whichKeyword(tok.ident) case whichKeyword(tok.ident)
of wIf: of wIf:
setLen(condStack, len(condStack) + 1) setLen(condStack, len(condStack) + 1)
var res = evalppIf(L, tok) let res = evalppIf(L, tok)
condStack[high(condStack)] = res condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif) if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok) of wElif: doElif(L, tok)
@ -224,8 +224,10 @@ proc loadConfigs*(cfg: string) =
if libpath == "": if libpath == "":
# choose default libpath: # choose default libpath:
var prefix = getPrefixDir() var prefix = getPrefixDir()
if prefix == "/usr": libpath = "/usr/lib/nimrod" when defined(posix):
elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod" 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") else: libpath = joinPath(prefix, "lib")
if optSkipConfigFile notin gGlobalOptions: if optSkipConfigFile notin gGlobalOptions:
@ -244,5 +246,6 @@ proc loadConfigs*(cfg: string) =
if gProjectName.len != 0: if gProjectName.len != 0:
# new project wide config file: # 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## exposes the Nimrod VM to clients. ## exposes the Nim VM to clients.
import import
ast, modules, passes, passaux, condsyms, ast, modules, passes, passaux, condsyms,

View file

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

View file

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

View file

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

View file

@ -1,13 +1,13 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# this unit handles Nimrod sets; it implements symbolic sets # this unit handles Nim sets; it implements symbolic sets
import import
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer 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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# 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. # to be changed.
const const
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets? MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
VersionMajor* = 0 VersionAsString* = system.NimVersion
VersionMinor* = 9
VersionPatch* = 7
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1215" # modify this if the rod-format changes! 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # also: generate header file
TGlobalOptions* = set[TGlobalOption] TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands TCommands* = enum # Nim's commands
# **keep binary compatible** # **keep binary compatible**
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
@ -114,7 +114,8 @@ var
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
# the tracked source X, saved by the CAAS client. # the tracked source X, saved by the CAAS client.
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer. 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 importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
@ -139,7 +140,7 @@ const
JsonExt* = "json" JsonExt* = "json"
TexExt* = "tex" TexExt* = "tex"
IniExt* = "ini" IniExt* = "ini"
DefaultConfig* = "nimrod.cfg" DefaultConfig* = "nim.cfg"
DocConfig* = "nimdoc.cfg" DocConfig* = "nimdoc.cfg"
DocTexConfig* = "nimdoc.tex.cfg" DocTexConfig* = "nimdoc.tex.cfg"
@ -152,7 +153,6 @@ var
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/ gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
gProjectFull* = "" # projectPath/projectName gProjectFull* = "" # projectPath/projectName
gProjectMainIdx*: int32 # the canonical path id of the main module gProjectMainIdx*: int32 # the canonical path id of the main module
optMainModule* = "" # the main module that should be used for idetools commands
nimcacheDir* = "" nimcacheDir* = ""
command* = "" # the main command (e.g. cc, check, scan, etc) command* = "" # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] = @[] # any arguments after the main command commandArgs*: seq[string] = @[] # any arguments after the main command
@ -189,8 +189,8 @@ proc getPrefixDir*(): string =
result = splitPath(getAppDir()).head result = splitPath(getAppDir()).head
proc canonicalizePath*(path: string): string = proc canonicalizePath*(path: string): string =
result = path.expandFilename when not FileSystemCaseSensitive: result = path.expandFilename.toLower
when not FileSystemCaseSensitive: result = result.toLower else: result = path.expandFilename
proc shortenDir*(dir: string): string = proc shortenDir*(dir: string): string =
## returns the interesting part of a dir ## 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 #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d] return packageCache[d]
inc parents inc parents
for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name
break packageSearch
for file in walkFiles(d / "*.babel"): for file in walkFiles(d / "*.babel"):
result = file.splitFile.name result = file.splitFile.name
break packageSearch break packageSearch
@ -295,7 +298,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
createDir(subdir) createDir(subdir)
when noTimeMachine: when noTimeMachine:
excludeDirFromTimeMachine(subdir) excludeDirFromTimeMachine(subdir)
except EOS: except OSError:
writeln(stdout, "cannot create directory: " & subdir) writeln(stdout, "cannot create directory: " & subdir)
quit(1) quit(1)
result = joinPath(subdir, tail) result = joinPath(subdir, tail)
@ -335,6 +338,16 @@ proc findFile*(f: string): string {.procvar.} =
proc findModule*(modulename, currentModule: string): string = proc findModule*(modulename, currentModule: string): string =
# returns path to module # 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 m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir let currentPath = currentModule.splitFile.dir
result = currentPath / m result = currentPath / m

View file

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

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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: # couldn't bind parameter:
if isNil(x): return nil if isNil(x): return nil
result.add(x) result.add(x)
if requiresAA: addToArgList(args, n) if requiresAA: addToArgList(args, x)
# perform alias analysis here: # perform alias analysis here:
if requiresAA: if requiresAA:
for i in 1 .. < params.len: for i in 1 .. < params.len:

View file

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

View file

@ -45,7 +45,7 @@ const
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt, wDeprecated} wInjectStmt, wDeprecated, wExperimental}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
@ -71,7 +71,7 @@ const
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation # implementation
proc invalidPragma(n: PNode) = proc invalidPragma(n: PNode) =
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments})) localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
proc pragmaAsm*(c: PContext, n: PNode): char = proc pragmaAsm*(c: PContext, n: PNode): char =
@ -130,6 +130,7 @@ proc processImportCpp(s: PSym, extname: string) =
excl(s.flags, sfForward) excl(s.flags, sfForward)
let m = s.getModule() let m = s.getModule()
incl(m.flags, sfCompileToCpp) incl(m.flags, sfCompileToCpp)
extccomp.gMixedMode = true
proc processImportObjC(s: PSym, extname: string) = proc processImportObjC(s: PSym, extname: string) =
setExternName(s, extname) setExternName(s, extname)
@ -356,11 +357,11 @@ proc processPush(c: PContext, n: PNode, start: int) =
append(c.optionStack, x) append(c.optionStack, x)
for i in countup(start, sonsLen(n) - 1): for i in countup(start, sonsLen(n) - 1):
if processOption(c, n.sons[i]): if processOption(c, n.sons[i]):
# simply store it somehwere: # simply store it somewhere:
if x.otherPragmas.isNil: if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info) x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n.sons[i] x.otherPragmas.add n.sons[i]
#LocalError(n.info, errOptionExpected) #localError(n.info, errOptionExpected)
proc processPop(c: PContext, n: PNode) = proc processPop(c: PContext, n: PNode) =
if c.optionStack.counter <= 1: if c.optionStack.counter <= 1:
@ -447,6 +448,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
addSon(result, newSymNode(e)) addSon(result, newSymNode(e))
else: else:
addSon(result, newStrNode(nkStrLit, sub)) addSon(result, newStrNode(nkStrLit, sub))
else:
# an empty '``' produces a single '`'
addSon(result, newStrNode(nkStrLit, $marker))
if c < 0: break if c < 0: break
a = c + 1 a = c + 1
else: illFormedAst(n) else: illFormedAst(n)
@ -518,6 +522,28 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
else: else:
invalidPragma(n) 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) = proc typeBorrow(sym: PSym, n: PNode) =
if n.kind == nkExprColonExpr: if n.kind == nkExprColonExpr:
let it = n.sons[1] let it = n.sons[1]
@ -575,6 +601,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if c.instCounter > 100: if c.instCounter > 100:
globalError(it.info, errRecursiveDependencyX, userPragma.name.s) globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas) 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 dec c.instCounter
else: else:
var k = whichKeyword(key.ident) var k = whichKeyword(key.ident)
@ -807,6 +836,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym == nil: invalidPragma(it) if sym == nil: invalidPragma(it)
of wLine: pragmaLine(c, it) of wLine: pragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(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: of wGuard:
if sym == nil or sym.kind notin {skVar, skLet, skField}: if sym == nil or sym.kind notin {skVar, skLet, skField}:
invalidPragma(it) invalidPragma(it)
@ -817,6 +850,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
localError(it.info, errExprExpected) localError(it.info, errExprExpected)
else: else:
it.sons[1] = c.semExpr(c, it.sons[1]) 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: invalidPragma(it) else: invalidPragma(it)
else: processNote(c, it) else: processNote(c, it)
@ -853,8 +892,13 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
return false 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 if n == nil: return
for i in countup(0, sonsLen(n) - 1): 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) 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -11,7 +11,7 @@
# This is needed for proper handling of forward declarations. # This is needed for proper handling of forward declarations.
import import
ast, astalgo, msgs, semdata, types, trees ast, astalgo, msgs, semdata, types, trees, strutils
proc equalGenericParams(procA, procB: PNode): bool = proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return if sonsLen(procA) != sonsLen(procB): return
@ -68,11 +68,17 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
ExactConstraints, IgnoreCC} ExactConstraints, IgnoreCC}
var it: TIdentIter var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name) result = initIdentIter(it, scope.symbols, fn.name)
while result != nil: while result != nil:
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags): if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
case equalParams(result.typ.n, fn.typ.n) case equalParams(result.typ.n, fn.typ.n)
of paramsEqual: 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 return
of paramsIncompatible: of paramsIncompatible:
localError(fn.info, errNotOverloadable, fn.name.s) 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 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module implements the renderer of the standard Nimrod representation. # This module implements the renderer of the standard Nim representation.
import import
lexer, options, idents, strutils, ast, msgs, lists lexer, options, idents, strutils, ast, msgs, lists
@ -34,6 +34,7 @@ type
comStack*: seq[PNode] # comment stack comStack*: seq[PNode] # comment stack
flags*: TRenderFlags flags*: TRenderFlags
checkAnon: bool # we're in a context that can contain sfAnon checkAnon: bool # we're in a context that can contain sfAnon
inPragma: int
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {}) 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): if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
incl(c.flags, rfLongMode) incl(c.flags, rfLongMode)
gcoms(g) # a good place for comments gcoms(g) # a good place for comments
gstmts(g, n.sons[0], c) gstmts(g, n, c)
put(g, tkCurlyRi, "}") put(g, tkCurlyRi, "}")
proc gpragmaBlock(g: var TSrcGen, n: PNode) = proc gpragmaBlock(g: var TSrcGen, n: PNode) =
@ -894,8 +895,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(") put(g, tkParLe, "(")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: put(g, tkOpr, "|") if i > 0: put(g, tkOpr, "|")
gsub(g, n.sons[i], c) if n.sons[i].kind == nkSym:
put(g, tkParRi, ")") 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: of nkPar, nkClosure:
put(g, tkParLe, "(") put(g, tkParLe, "(")
gcomma(g, n, c) gcomma(g, n, c)
@ -940,10 +948,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, -3) gcomma(g, n, 0, -3)
var L = sonsLen(n) var L = sonsLen(n)
if n.sons[L - 2].kind != nkEmpty: if L >= 2 and n.sons[L - 2].kind != nkEmpty:
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gsub(g, n.sons[L - 2]) 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) put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[L - 1], c) gsub(g, n.sons[L - 1], c)
@ -1009,9 +1017,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkElse, " else") put(g, tkElse, " else")
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkTypeOfExpr: of nkTypeOfExpr:
putWithSpace(g, tkType, "type") putWithSpace(g, tkType, "type")
gsub(g, n.sons[0]) if n.len > 0: gsub(g, n.sons[0])
of nkRefTy: of nkRefTy:
if sonsLen(n) > 0: if sonsLen(n) > 0:
putWithSpace(g, tkRef, "ref") putWithSpace(g, tkRef, "ref")
@ -1177,12 +1185,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkContinueStmt: of nkContinueStmt:
putWithSpace(g, tkContinue, "continue") putWithSpace(g, tkContinue, "continue")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkPragma: of nkPragma:
if renderNoPragmas notin g.flags: if renderNoPragmas notin g.flags:
put(g, tkSpaces, Space) if g.inPragma <= 0:
put(g, tkCurlyDotLe, "{.") inc g.inPragma
gcomma(g, n, emptyContext) put(g, tkSpaces, Space)
put(g, tkCurlyDotRi, ".}") put(g, tkCurlyDotLe, "{.")
gcomma(g, n, emptyContext)
put(g, tkCurlyDotRi, ".}")
dec g.inPragma
else:
gcomma(g, n, emptyContext)
of nkImportStmt, nkExportStmt: of nkImportStmt, nkExportStmt:
if n.kind == nkImportStmt: if n.kind == nkImportStmt:
putWithSpace(g, tkImport, "import") putWithSpace(g, tkImport, "import")
@ -1306,7 +1319,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
proc renderModule(n: PNode, filename: string, proc renderModule(n: PNode, filename: string,
renderFlags: TRenderFlags = {}) = renderFlags: TRenderFlags = {}) =
var var
f: TFile f: File
g: TSrcGen g: TSrcGen
initSrcGen(g, renderFlags) initSrcGen(g, renderFlags)
for i in countup(0, sonsLen(n) - 1): 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -121,7 +121,7 @@ type
r*: string # writers use this r*: string # writers use this
offset*: int # readers use this offset*: int # readers use this
TRodReader* = object of TObject TRodReader* = object of RootObj
pos: int # position; used for parsing pos: int # position; used for parsing
s: cstring # mmap'ed file contents s: cstring # mmap'ed file contents
options: TOptions options: TOptions
@ -137,7 +137,7 @@ type
line: int # only used for debugging, but is always in the code line: int # only used for debugging, but is always in the code
moduleID: int moduleID: int
syms: TIdTable # already processed symbols 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 # can close this! XXX
methods*: TSymSeq methods*: TSymSeq
origFile: string origFile: string
@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.r = toRope(decodeStr(r.s, r.pos)) loc.r = toRope(decodeStr(r.s, r.pos))
else: else:
loc.r = nil 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) if r.s[r.pos] == '>': inc(r.pos)
else: internalError(info, "decodeLoc " & r.s[r.pos]) else: internalError(info, "decodeLoc " & r.s[r.pos])
@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
result.size = - 1 result.size = - 1
if r.s[r.pos] == '=': if r.s[r.pos] == '=':
inc(r.pos) inc(r.pos)
result.align = decodeVInt(r.s, r.pos) result.align = decodeVInt(r.s, r.pos).int16
else: else:
result.align = 2 result.align = 2
decodeLoc(r, result.loc, info) decodeLoc(r, result.loc, info)
@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
idTablePut(r.syms, s, s) idTablePut(r.syms, s, s)
strTableAdd(rodCompilerprocs, 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 var key, val, tmp: int
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
new(result) new(result)
try: try:
result.memfile = memfiles.open(modfilename) result.memfile = memfiles.open(modfilename)
except EOS: except OSError:
return nil return nil
result.files = @[] result.files = @[]
result.modDeps = @[] result.modDeps = @[]
@ -916,7 +911,7 @@ initIdTable(gTypeTable)
initStrTable(rodCompilerprocs) initStrTable(rodCompilerprocs)
# viewer: # viewer:
proc writeNode(f: TFile; n: PNode) = proc writeNode(f: File; n: PNode) =
f.write("(") f.write("(")
if n != nil: if n != nil:
f.write($n.kind) f.write($n.kind)
@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) =
writeNode(f, n.sons[i]) writeNode(f, n.sons[i])
f.write(")") f.write(")")
proc writeSym(f: TFile; s: PSym) = proc writeSym(f: File; s: PSym) =
if s == nil: if s == nil:
f.write("{}\n") f.write("{}\n")
return return
@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) =
f.writeNode(s.ast) f.writeNode(s.ast)
f.write("}\n") f.write("}\n")
proc writeType(f: TFile; t: PType) = proc writeType(f: File; t: PType) =
if t == nil: if t == nil:
f.write("[]\n") f.write("[]\n")
return return

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -12,7 +12,7 @@
# Ropes are a data structure that represents a very long string # Ropes are a data structure that represents a very long string
# efficiently; especially concatenation is done in O(1) instead of O(N). # efficiently; especially concatenation is done in O(1) instead of O(N).
# Ropes make use a lazy evaluation: They are essentially concatenation # 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 # string or when written to disk. The empty string is represented by a
# nil pointer. # nil pointer.
# A little picture makes everything clear: # A little picture makes everything clear:
@ -64,7 +64,7 @@ type
# copy the format strings # copy the format strings
# though it is not necessary) # though it is not necessary)
PRope* = ref TRope 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 # by nil to safe space
left*, right*: PRope left*, right*: PRope
length*: int 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 app(a: var PRope, b: string) = a = con(a, b)
proc prepend(a: var PRope, b: PRope) = a = con(b, a) 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] var stack = @[c]
while len(stack) > 0: while len(stack) > 0:
var it = pop(stack) var it = pop(stack)
@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) =
write(f, it.data) write(f, it.data)
proc writeRope*(head: PRope, filename: string, useWarning = false) = proc writeRope*(head: PRope, filename: string, useWarning = false) =
var f: TFile var f: File
if open(f, filename, fmWrite): if open(f, filename, fmWrite):
if head != nil: writeRope(f, head) if head != nil: writeRope(f, head)
close(f) close(f)
@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
const const
bufSize = 1024 # 1 KB is reasonable 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.data != nil:
if r.length > bufSize: if r.length > bufSize:
errorHandler(rTokenTooLong, r.data) 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) if result: result = auxRopeEqualsFile(r.right, bin, buf)
proc ropeEqualsFile(r: PRope, f: string): bool = proc ropeEqualsFile(r: PRope, f: string): bool =
var bin: TFile var bin: File
result = open(bin, f) result = open(bin, f)
if not result: if not result:
return # not equal if file does not exist 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -15,9 +15,12 @@ import
magicsys, parser, nversion, nimsets, semfold, importer, magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity, evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings semparallel, lowerings
when defined(nimfix):
import nimfix.prettybase
# implementation # implementation
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.} 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 addParams(c: PContext, n: PNode, kind: TSymKind)
proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc maybeAddResult(c: PContext, s: PSym, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
flags: TExprFlags = {}, bufferErrors = false): PNode
proc fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode) proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym) proc finishMethod(c: PContext, s: PSym)
@ -66,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
# error correction: # error correction:
result = copyTree(arg) result = copyTree(arg)
result.typ = formal 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, proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode arg: PNode, coerceDistincts = false): PNode
var commonTypeBegin = PType(kind: tyExpr) 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 = proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors, # new type relation that is used for array constructors,
# if expressions, etc.: # if expressions, etc.:
@ -95,6 +109,13 @@ proc commonType*(x, y: PType): PType =
# check for seq[empty] vs. seq[int] # check for seq[empty] vs. seq[int]
let idx = ord(b.kind in {tyArray, tyArrayConstr}) let idx = ord(b.kind in {tyArray, tyArrayConstr})
if a.sons[idx].kind == tyEmpty: return y 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 b.sons[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange: elif a.kind == tyRange and b.kind == tyRange:
# consider: (range[0..3], range[0..4]) here. We should make that # 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 = newType(k, r.owner)
result.addSonSkipIntLit(r) result.addSonSkipIntLit(r)
proc isTopLevel(c: PContext): bool {.inline.} =
result = c.currentScope.depthLevel <= 2
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# like newSymS, but considers gensym'ed symbols # like newSymS, but considers gensym'ed symbols
if n.kind == nkSym: if n.kind == nkSym:
# and sfGenSym in n.sym.flags:
result = n.sym result = n.sym
internalAssert sfGenSym in result.flags
internalAssert result.kind == kind internalAssert result.kind == kind
# when there is a nested proc inside a template, semtmpl # when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the # 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) pushInfoContext(nOrig.info)
markUsed(n.info, sym) markUsed(n.info, sym)
styleCheckUse(n.info, sym)
if sym == c.p.owner: if sym == c.p.owner:
globalError(n.info, errRecursiveDependencyX, sym.name.s) globalError(n.info, errRecursiveDependencyX, sym.name.s)
@ -340,7 +359,7 @@ type
TSemGenericFlags = set[TSemGenericFlag] TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode ctx: var IntSet): PNode
include semtypes, semtempl, semgnrc, semstmts, semexprs include semtypes, semtempl, semgnrc, semstmts, semexprs
@ -367,6 +386,8 @@ proc myOpen(module: PSym): PPassContext =
c.semInferredLambda = semInferredLambda c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode c.semTypeNode = semTypeNode
c.instDeepCopy = sigmatch.instDeepCopy
pushProcCon(c, module) pushProcCon(c, module)
pushOwner(c.module) pushOwner(c.module)
c.importTable = openScope(c) 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
initialBinding: PNode, initialBinding: PNode,
filter: TSymKinds, filter: TSymKinds,
best, alt: var TCandidate, best, alt: var TCandidate,
errors: var seq[string]) = errors: var CandidateErrors) =
var o: TOverloadIter var o: TOverloadIter
var sym = initOverloadIter(o, c, headSymbol) var sym = initOverloadIter(o, c, headSymbol)
var symScope = o.lastOverloadScope var symScope = o.lastOverloadScope
@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
z.calleeSym = sym z.calleeSym = sym
matches(c, n, orig, z) matches(c, n, orig, z)
if errors != nil: if errors != nil:
errors.safeAdd(getProcHeader(sym)) errors.safeAdd(sym)
if z.errors != nil: if z.errors != nil:
for err in z.errors: for err in z.errors:
errors[errors.len - 1].add("\n " & err) errors.add(err)
if z.state == csMatch: if z.state == csMatch:
# little hack so that iterators are preferred over everything else: # little hack so that iterators are preferred over everything else:
if sym.kind in skIterators: inc(z.exactMatches, 200) if sym.kind in skIterators: inc(z.exactMatches, 200)
@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
else: discard else: discard
sym = nextOverloadIter(o, c, headSymbol) 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, # Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information # as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error). # only in case of an error).
@ -83,18 +83,38 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
globalError(n.info, errTypeMismatch, "") globalError(n.info, errTypeMismatch, "")
if errors.len == 0: if errors.len == 0:
localError(n.info, errExprXCannotBeCalled, n[0].renderTree) localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1)) # to avoid confusing errors like:
add(result, ')') # 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 = "" var candidates = ""
for err in errors: for err in errors:
add(candidates, err) add(candidates, err.getProcHeader(prefer))
add(candidates, "\n") add(candidates, "\n")
if candidates != "": if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
localError(n.info, errGenerated, result) localError(n.info, errGenerated, result)
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) = proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
@ -114,7 +134,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else: else:
initialBinding = nil initialBinding = nil
var errors: seq[string] var errors: CandidateErrors
var usedSyms: seq[PNode] var usedSyms: seq[PNode]
template pickBest(headSymbol: expr) = template pickBest(headSymbol: expr) =
@ -254,6 +274,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch assert x.state == csMatch
var finalCallee = x.calleeSym var finalCallee = x.calleeSym
markUsed(n.sons[0].info, finalCallee) markUsed(n.sons[0].info, finalCallee)
styleCheckUse(n.sons[0].info, finalCallee)
if finalCallee.ast == nil: if finalCallee.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty: 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) initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, m.bindings, n.info) var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(newInst, n.info) result = newSymNode(newInst, n.info)
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 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) result = explicitGenericSym(c, n, s)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}: elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters. # 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. # It's good enough for now.
result = newNodeI(a.kind, n.info) result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1): 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -57,7 +57,7 @@ type
# can access private object fields # can access private object fields
instCounter*: int # to prevent endless instantiations 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!) # store this info in the syms themselves!)
inTypeClass*: int # > 0 if we are in a user-defined type class inTypeClass*: int # > 0 if we are in a user-defined type class
inGenericContext*: int # > 0 if we are in a generic type inGenericContext*: int # > 0 if we are in a generic type
@ -72,8 +72,7 @@ type
libs*: TLinkedList # all libs used by this module libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}, semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
bufferErrors = false): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet 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 semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files includedFiles*: IntSet # used to detect recursive include files
userPragmas*: TStrTable userPragmas*: TStrTable
evalContext*: PEvalContext evalContext*: PEvalContext
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent unknownIdents*: IntSet # ids of all unknown identifiers to prevent
# naming it multiple times # naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
lastGenericIdx*: int # used for the generics stack lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int inParallelStmt*: int
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
info: TLineInfo): PSym {.nimcall.}
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s result.genericSym = s
@ -310,3 +312,8 @@ proc checkSonsLen*(n: PNode, length: int) =
proc checkMinSonsLen*(n: PNode, length: int) = proc checkMinSonsLen*(n: PNode, length: int) =
if sonsLen(n) < length: illFormedAst(n) 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -13,6 +13,7 @@
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode = flags: TExprFlags = {}): PNode =
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
pushInfoContext(n.info) pushInfoContext(n.info)
result = evalTemplate(n, s, getCurrOwner()) result = evalTemplate(n, s, getCurrOwner())
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) 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 case s.kind
of skConst: of skConst:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64: 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 skTemplate: result = semTemplateExpr(c, n, s, flags)
of skVar, skLet, skResult, skParam, skForVar: of skVar, skLet, skResult, skParam, skForVar:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free: # if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect) 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 # var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure? # genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam: of skGenericParam:
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic: if s.typ.kind == tyStatic:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = s.typ result.typ = s.typ
@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
return n return n
of skType: of skType:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.n != nil: if s.typ.kind == tyStatic and s.typ.n != nil:
return s.typ.n return s.typ.n
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ) result.typ = makeTypeDesc(c, s.typ)
else: else:
markUsed(n.info, s) markUsed(n.info, s)
styleCheckUse(n.info, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
type type
@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
let status = checkConvertible(c, result.typ, it.typ) let status = checkConvertible(c, result.typ, it.typ)
if status in {convOK, convNotNeedeed}: if status in {convOK, convNotNeedeed}:
markUsed(n.info, it.sym) markUsed(n.info, it.sym)
styleCheckUse(n.info, it.sym)
markIndirect(c, it.sym) markIndirect(c, it.sym)
return it return it
localError(n.info, errUseQualifier, op.sons[0].sym.name.s) 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 result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and t.callConv == ccClosure and
tfIterator notin t.flags)) tfIterator notin t.flags))
else: discard
else: else:
var t2 = n[2].typ.skipTypes({tyTypeDesc}) var t2 = n[2].typ.skipTypes({tyTypeDesc})
maybeLiftType(t2, c, n.info) 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]) for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
result = semExpr(c, result) result = semExpr(c, result)
proc changeType(n: PNode, newType: PType, check: bool) = proc changeType(n: PNode, newType: PType, check: bool) =
case n.kind case n.kind
of nkCurly, nkBracket: of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType), check) changeType(n.sons[i], elemType(newType), check)
of nkPar: of nkPar:
if newType.kind != tyTuple: let tup = newType.skipTypes({tyGenericInst})
if tup.kind != tyTuple:
internalError(n.info, "changeType: no tuple type for constructor") 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: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i] var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) if m.kind == nkExprColonExpr:
addSon(a, newSymNode(newType.n.sons[i].sym)) m = m.sons[1]
addSon(a, m) n.sons[i] = m
changeType(m, newType.sons[i], check) changeType(m, tup.sons[i], check)
n.sons[i] = a
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if check: if check:
let value = n.intVal let value = n.intVal
@ -533,7 +529,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
elif skipTypes(it.sons[1].typ, abstractVar).kind in elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}: {tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar) 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] n.sons[i] = it.sons[1]
of nkBracket: of nkBracket:
# an implicitly constructed array (passed to an open array): # an implicitly constructed array (passed to an open array):
@ -721,7 +718,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
case callee.kind case callee.kind
of skMacro, skTemplate: discard of skMacro, skTemplate: discard
else: 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) localError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags: if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * 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) if result != nil: result = afterCallActions(c, result, nOrig, flags)
else: result = errorNode(c, n) 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 = 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) result = newNodeI(nkCall, n.info)
var e = strTableGet(magicsys.systemModule.tab, getIdent"echo") var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
if e != nil: if e != nil:
addSon(result, newSymNode(e)) add(result, newSymNode(e))
else: else:
localError(n.info, errSystemNeeds, "echo") localError(n.info, errSystemNeeds, "echo")
addSon(result, errorNode(c, n)) add(result, errorNode(c, n))
var arg = buildStringify(c, n) add(result, n)
# problem is: implicit '$' is not checked for semantics yet. So we give up result = semExpr(c, result)
# and check 'arg' for semantics again:
arg = semExpr(c, arg)
if arg != nil: addSon(result, arg)
proc semExprNoType(c: PContext, n: PNode): PNode = proc semExprNoType(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {efWantStmt}) result = semExpr(c, n, {efWantStmt})
@ -958,17 +927,18 @@ proc readTypeParameter(c: PContext, typ: PType,
paramName: PIdent, info: TLineInfo): PNode = paramName: PIdent, info: TLineInfo): PNode =
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1]) else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
#debug ty
let tbody = ty.sons[0] let tbody = ty.sons[0]
for s in countup(0, tbody.len-2): for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s] let tParam = tbody.sons[s]
if tParam.sym.name == paramName: if tParam.sym.name.id == paramName.id:
let rawTyp = ty.sons[s + 1] let rawTyp = ty.sons[s + 1]
if rawTyp.kind == tyStatic: if rawTyp.kind == tyStatic:
return rawTyp.n return rawTyp.n
else: else:
let foundTyp = makeTypeDesc(c, rawTyp) let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
#echo "came here: returned nil"
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access ## 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}) var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if s != nil: if s != nil:
markUsed(n.sons[1].info, s) if s.kind in OverloadableSyms:
return semSym(c, n, s, flags) 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}) n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
#restoreOldStyleType(n.sons[0]) #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: # look up if the identifier belongs to the enum:
while ty != nil: while ty != nil:
f = getSymFromList(ty.n, i) f = getSymFromList(ty.n, i)
if f != nil: break if f != nil: break
ty = ty.sons[0] # enum inheritance ty = ty.sons[0] # enum inheritance
if f != nil: if f != nil:
result = newSymNode(f) result = newSymNode(f)
result.info = n.info result.info = n.info
result.typ = ty result.typ = ty
markUsed(n.info, f) markUsed(n.info, f)
styleCheckUse(n.info, f)
return return
of tyTypeParamsHolders: of tyTypeParamsHolders:
return readTypeParameter(c, ty, i, n.info) return readTypeParameter(c, ty, i, n.info)
@ -1036,12 +1013,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
if fieldVisible(c, f): if fieldVisible(c, f):
# is the access to a public field or in the same module or in a friend? # is the access to a public field or in the same module or in a friend?
markUsed(n.sons[1].info, f) markUsed(n.sons[1].info, f)
styleCheckUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f) # we now have the correct field n.sons[1] = newSymNode(f) # we now have the correct field
n.typ = f.typ n.typ = f.typ
if check == nil: if check == nil:
result = n result = n
else: else:
check.sons[0] = n check.sons[0] = n
check.typ = n.typ check.typ = n.typ
result = check result = check
@ -1049,6 +1027,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
f = getSymFromList(ty.n, i) f = getSymFromList(ty.n, i)
if f != nil: if f != nil:
markUsed(n.sons[1].info, f) markUsed(n.sons[1].info, f)
styleCheckUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f) n.sons[1] = newSymNode(f)
n.typ = f.typ n.typ = f.typ
@ -1260,8 +1239,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
proc semReturn(c: PContext, n: PNode): PNode = proc semReturn(c: PContext, n: PNode): PNode =
result = n result = n
checkSonsLen(n, 1) checkSonsLen(n, 1)
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
c.p.owner.kind == skClosureIterator: skClosureIterator}:
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return`` # transform ``return expr`` to ``result = expr; return``
if c.p.resultSym != nil: if c.p.resultSym != nil:
@ -1444,6 +1423,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
proc semUsing(c: PContext, n: PNode): PNode = proc semUsing(c: PContext, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info) result = newNodeI(nkEmpty, n.info)
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
for e in n.sons: for e in n.sons:
let usedSym = semExpr(c, e) let usedSym = semExpr(c, e)
if usedSym.kind == nkSym: if usedSym.kind == nkSym:
@ -1465,6 +1446,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
markUsed(n.info, expandedSym) markUsed(n.info, expandedSym)
styleCheckUse(n.info, expandedSym)
for i in countup(1, macroCall.len-1): for i in countup(1, macroCall.len-1):
macroCall.sons[i] = semExprWithType(c, macroCall[i], {}) 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 doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
if ids.len > 0: if ids.len > 0:
doBlk[paramsPos].sons.setLen(2) doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
ids.add getSysSym("expr").newSymNode # params type ids.add getSysSym("expr").newSymNode # params type
ids.add emptyNode # no default value 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) var tmpl = semTemplateDef(c, doBlk)
quotes[0] = tmpl[namePos] quotes[0] = tmpl[namePos]
@ -1538,8 +1520,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
newNode(nkCall, n.info, quotes)]) newNode(nkCall, n.info, quotes)])
result = semExpandToAst(c, result) result = semExpandToAst(c, result)
proc tryExpr(c: PContext, n: PNode, proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}, bufferErrors = false): PNode =
# watch out, hacks ahead: # watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax let oldErrorMax = msgs.gErrorMax
@ -1553,7 +1534,7 @@ proc tryExpr(c: PContext, n: PNode,
let oldOwnerLen = len(gOwners) let oldOwnerLen = len(gOwners)
let oldGenerics = c.generics let oldGenerics = c.generics
let oldErrorOutputs = errorOutputs let oldErrorOutputs = errorOutputs
errorOutputs = if bufferErrors: {eInMemory} else: {} errorOutputs = {}
let oldContextLen = msgs.getInfoContextLen() let oldContextLen = msgs.getInfoContextLen()
let oldInGenericContext = c.inGenericContext 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 mSizeOf: result = semSizeof(c, setMs(n, s))
of mIs: result = semIs(c, setMs(n, s)) of mIs: result = semIs(c, setMs(n, s))
of mOf: result = semOf(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 mShallowCopy: result = semShallowCopy(c, n, flags)
of mExpandToAst: result = semExpandToAst(c, n, s, flags) of mExpandToAst: result = semExpandToAst(c, n, s, flags)
of mQuoteAst: result = semQuoteAst(c, n) of mQuoteAst: result = semQuoteAst(c, n)
@ -1662,6 +1642,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: else:
result.typ = result[1].typ result.typ = result[1].typ
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode 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) else: result = semDirectOp(c, n, flags)
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = 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) addSonSkipIntLit(typ, n.sons[i].typ)
result.typ = typ result.typ = typ
proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) = proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -1902,6 +1886,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
addDecl(c, labl) addDecl(c, labl)
n.sons[0] = newSymNode(labl, n.sons[0].info) n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(n.sons[0].info, labl) suggestSym(n.sons[0].info, labl)
styleCheckDef(labl)
n.sons[1] = semExpr(c, n.sons[1]) n.sons[1] = semExpr(c, n.sons[1])
n.typ = n.sons[1].typ n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt if isEmptyType(n.typ): n.kind = nkBlockStmt
@ -1909,19 +1894,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
closeScope(c) closeScope(c)
dec(c.p.nestedBlockCounter) 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 = proc semExport(c: PContext, n: PNode): PNode =
var x = newNodeI(n.kind, n.info) var x = newNodeI(n.kind, n.info)
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len #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 o: TOverloadIter
var s = initOverloadIter(o, c, a) var s = initOverloadIter(o, c, a)
if s == nil: if s == nil:
localError(a.info, errGenerated, "invalid expr for 'export': " & localError(a.info, errGenerated, "cannot export: " & renderTree(a))
renderTree(a)) elif s.kind == skModule:
while s != nil: # forward everything from that module:
if s.kind in ExportableSymKinds+{skModule}: strTableAdd(c.module.tab, s)
x.add(newSymNode(s, a.info)) x.add(newSymNode(s, a.info))
strTableAdd(c.module.tab, s) var ti: TTabIter
s = nextOverloadIter(o, c, a) 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: when false:
if c.module.ast.isNil: if c.module.ast.isNil:
c.module.ast = newNodeI(nkStmtList, n.info) c.module.ast = newNodeI(nkStmtList, n.info)
@ -2021,22 +2003,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
let mode = if nfDotField in n.flags: {} else: {checkUndeclared} let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
var s = qualifiedLookUp(c, n.sons[0], mode) var s = qualifiedLookUp(c, n.sons[0], mode)
if s != nil: if s != nil:
if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
pretty.checkUse(n.sons[0].sons[1].info, s) # pretty.checkUse(n.sons[0].sons[1].info, s)
case s.kind case s.kind
of skMacro: of skMacro:
if sfImmediate notin s.flags: if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
var p = fixImmediateParams(n) result = semMacroExpr(c, n, n, s, flags)
result = semMacroExpr(c, p, p, s, flags)
of skTemplate: of skTemplate:
if sfImmediate notin s.flags: if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
var p = fixImmediateParams(n) result = semTemplateExpr(c, n, s, flags)
result = semTemplateExpr(c, p, s, flags)
of skType: of skType:
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: 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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -197,18 +197,20 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
of mSubI, mSubI64, mSubU: of mSubI, mSubI64, mSubU:
binaryOp(`|-|`) binaryOp(`|-|`)
of mBitandI, mBitandI64: 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 a = n.sons[1]
var b = n.sons[2] var b = n.sons[2]
# symmetrical: # symmetrical:
if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b) if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
if b.kind in {nkIntLit..nkUInt64Lit}: if b.kind in {nkIntLit..nkUInt32Lit}:
let x = b.intVal|+|1 let x = b.intVal|+|1
if (x and -x) == x and x >= 0: if (x and -x) == x and x >= 0:
result = makeRange(a.typ, 0, b.intVal) result = makeRange(a.typ, 0, b.intVal)
of mModU: of mModU:
let a = n.sons[1] let a = n.sons[1]
let b = n.sons[2] let b = n.sons[2]
if b.kind in {nkIntLit..nkUInt64Lit}: if b.kind in {nkIntLit..nkUInt32Lit}:
if b.intVal >= 0: if b.intVal >= 0:
result = makeRange(a.typ, 0, b.intVal-1) result = makeRange(a.typ, 0, b.intVal-1)
else: else:
@ -255,6 +257,7 @@ proc evalIs(n, a: PNode): PNode =
result = newIntNode(nkIntLit, ord(t.kind == tyProc and result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure and t.callConv == ccClosure and
tfIterator in t.flags)) tfIterator in t.flags))
else: discard
else: else:
# XXX semexprs.isOpImpl is slightly different and requires a context. yay. # XXX semexprs.isOpImpl is slightly different and requires a context. yay.
let t2 = n[2].typ let t2 = n[2].typ
@ -318,8 +321,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt64, tyInt, tyUInt..tyUInt64: of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n) result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: internalError(n.info, "constant folding for shr") else: internalError(n.info, "constant folding for shr")
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n) of mDivI, mDivI64:
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n) 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 mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
of mSubF64: 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) 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 mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
of mSubU: 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 mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n) of mModU:
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n) 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 mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n) of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
of mLtSet: of mLtSet:
@ -501,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
of tyInt..tyInt64: of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
result = newIntNodeT(system.toInt(getFloat(a)), n) result = newIntNodeT(int(getFloat(a)), n)
of tyChar: result = newIntNodeT(getOrdValue(a), n) of tyChar: result = newIntNodeT(getOrdValue(a), n)
else: else:
result = a result = a
@ -600,10 +615,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
of mCompileTime: result = newStrNodeT(times.getClockStr(), 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 mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n) of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, 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) result = evalIs(n, a)
else: else:
result = magicCall(m, n) result = magicCall(m, n)
except EOverflow: except OverflowError:
localError(n.info, errOverOrUnderflow) localError(n.info, errOverOrUnderflow)
except EDivByZero: except DivByZeroError:
localError(n.info, errConstantDivisionByZero) localError(n.info, errConstantDivisionByZero)
of nkAddr: of nkAddr:
var a = getConstExpr(m, n.sons[0]) var a = getConstExpr(m, n.sons[0])

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # 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! # as in ``var x = ...`` or used because macros/templates can hide this!
# So we have to eval templates/macros right here so that symbol # 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 # included from sem.nim
@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode =
proc semGenericStmtScope(c: PContext, n: PNode, proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags, flags: TSemGenericFlags,
ctx: var TIntSet): PNode = ctx: var IntSet): PNode =
openScope(c) openScope(c)
result = semGenericStmt(c, n, flags, ctx) result = semGenericStmt(c, n, flags, ctx)
closeScope(c) 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) s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var TIntSet): PNode = ctx: var IntSet): PNode =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
case s.kind case s.kind
of skUnknown: of skUnknown:
@ -47,33 +47,39 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skTemplate: of skTemplate:
if macroToExpand(s): if macroToExpand(s):
let n = fixImmediateParams(n) styleCheckUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skMacro: of skMacro:
if macroToExpand(s): if macroToExpand(s):
styleCheckUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skGenericParam: of skGenericParam:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
of skParam: styleCheckUse(n.info, s)
of skParam:
result = n result = n
styleCheckUse(n.info, s)
of skType: of skType:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
else: else:
result = n 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, proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode = ctx: var IntSet): PNode =
result = n result = n
let ident = considerQuotedIdent(n) let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident) var s = searchInScopes(c, ident).skipAlias(n)
if s == nil: if s == nil:
if ident.id notin ctx and withinMixin notin flags: if ident.id notin ctx and withinMixin notin flags:
localError(n.info, errUndeclaredIdentifier, ident.s) localError(n.info, errUndeclaredIdentifier, ident.s)
@ -92,7 +98,7 @@ proc newDot(n, b: PNode): PNode =
result.add(b) result.add(b)
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var TIntSet): PNode = ctx: var IntSet; isMacro: var bool): PNode =
assert n.kind == nkDotExpr assert n.kind == nkDotExpr
let luf = if withinMixin notin flags: {checkUndeclared} else: {} let luf = if withinMixin notin flags: {checkUndeclared} else: {}
@ -104,8 +110,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
result = n result = n
let n = n[1] let n = n[1]
let ident = considerQuotedIdent(n) let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident) var s = searchInScopes(c, ident).skipAlias(n)
if s != nil and s.kind in routineKinds: if s != nil and s.kind in routineKinds:
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags: if withinBind in flags:
result = newDot(result, symChoice(c, n, s, scClosed)) result = newDot(result, symChoice(c, n, s, scClosed))
elif s.name.id in ctx: elif s.name.id in ctx:
@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
else: else:
result = newDot(result, sym) 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, proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var TIntSet): PNode = flags: TSemGenericFlags, ctx: var IntSet): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestStmt(c, n) if gCmd == cmdIdeTools: suggestStmt(c, n)
case n.kind case n.kind
@ -129,7 +141,8 @@ proc semGenericStmt(c: PContext, n: PNode,
#var s = qualifiedLookUp(c, n, luf) #var s = qualifiedLookUp(c, n, luf)
#if s != nil: result = semGenericStmtSymbol(c, n, s) #if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here... # 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: of nkEmpty, nkSym..nkNilLit:
# see tests/compile/tgensymgeneric.nim: # see tests/compile/tgensymgeneric.nim:
# We need to open the gensym'ed symbol again so that the instantiation # 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) localError(n.info, errUndeclaredIdentifier, fn.renderTree)
var first = 0 var first = 0
var isDefinedMagic = false var mixinContext = false
if s != nil: if s != nil:
incl(s.flags, sfUsed) 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 let scOption = if s.name.id in ctx: scForceOpen else: scOpen
case s.kind case s.kind
of skMacro: of skMacro:
if macroToExpand(s): if macroToExpand(s):
styleCheckUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption) n.sons[0] = symChoice(c, fn, s, scOption)
result = n result = n
of skTemplate: mixinContext = true
of skTemplate:
if macroToExpand(s): if macroToExpand(s):
let n = fixImmediateParams(n) styleCheckUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
n.sons[0] = symChoice(c, n.sons[0], s, scOption) n.sons[0] = symChoice(c, fn, s, scOption)
result = n result = n
# BUGFIX: we must not return here, we need to do first phase of # 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: of skUnknown, skParam:
# Leave it as an identifier. # Leave it as an identifier.
discard discard
of skProc, skMethod, skIterators, skConverter: 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 first = 1
of skGenericParam: of skGenericParam:
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info) result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s)
first = 1 first = 1
of skType: of skType:
# bad hack for generics: # bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): 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 first = 1
else: else:
result.sons[0] = newSymNode(s, n.sons[0].info) result.sons[0] = newSymNode(s, fn.info)
styleCheckUse(fn.info, s)
first = 1 first = 1
elif fn.kind == nkDotExpr:
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
first = 1
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
# is not exported and yet the generic 'threadProcWrapper' works correctly. # 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): for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
of nkIfStmt: of nkIfStmt:
@ -226,14 +250,14 @@ proc semGenericStmt(c: PContext, n: PNode,
openScope(c) openScope(c)
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
for i in countup(0, L - 3): 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) n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
closeScope(c) closeScope(c)
of nkBlockStmt, nkBlockExpr, nkBlockType: of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2) checkSonsLen(n, 2)
openScope(c) openScope(c)
if n.sons[0].kind != nkEmpty: 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) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
closeScope(c) closeScope(c)
of nkTryStmt: 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-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3): 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: of nkGenericParams:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] 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) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions # do not perform symbol lookup for default expressions
for j in countup(0, L-3): 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: of nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): illFormedAst(a) if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3) 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[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
of nkTypeSection: of nkTypeSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a) if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3) 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): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
@ -306,9 +330,9 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkIdent: a = n.sons[i] of nkIdent: a = n.sons[i]
else: illFormedAst(n) else: illFormedAst(n)
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c)) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
of nkObjectTy, nkTupleTy: of nkObjectTy, nkTupleTy:
discard discard
of nkFormalParams: of nkFormalParams:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) 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-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3): 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, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambdaKinds: nkIteratorDef, nkLambdaKinds:
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
if n.kind notin nkLambdaKinds: if n.sons[namePos].kind != nkEmpty:
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c)) addTempDecl(c, getIdentNode(n.sons[0]), skProc)
openScope(c) openScope(c)
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
flags, ctx) flags, ctx)
if n.sons[paramsPos].kind != nkEmpty: 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)) addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], 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 # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 # The solution would be to move this logic into semtypinst, but
# at this point semtypinst have to become part of sem, because it # 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) addDecl(c, prc)
pushInfoContext(info) pushInfoContext(info)
@ -223,7 +222,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
n.sons[genericParamsPos] = ast.emptyNode n.sons[genericParamsPos] = ast.emptyNode
var oldPrc = genericCacheGet(fn, entry[]) var oldPrc = genericCacheGet(fn, entry[])
if oldPrc == nil: 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)) c.generics.add(makeInstPair(fn, entry))
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas) pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n) of mNBindSym: result = semBindSym(c, n)
of mLocals: result = semLocals(c, n) of mLocals: result = semLocals(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
else: result = n else: result = n

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 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) = proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
if op.magic == mSpawn: if op.magic == mSpawn:
inc c.spawns pushSpawnId(c):
let oldSpawnId = c.currentSpawnId gatherArgs(c, n[1])
c.currentSpawnId = c.spawns analyseSons(c, n)
gatherArgs(c, n[1])
analyseSons(c, n)
c.currentSpawnId = oldSpawnId
elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem): elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
if n[1].isLocal: if n[1].isLocal:
let incr = n[2].skipConv 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 # since we already ensure sfAddrTaken is not in s.flags, we only need to
# prevent direct assignments to the monotonic variable: # prevent direct assignments to the monotonic variable:
let slot = c.getSlot(n[0].sym) let slot = c.getSlot(n[0].sym)
slot.blackListed = true slot.blacklisted = true
invalidateFacts(c.guards, n[0]) 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]) addAsgnFact(c.guards, n[0], n[1])
of nkCallKinds: of nkCallKinds:
# direct call: # direct call:
@ -335,16 +346,21 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
localError(n.info, "invalid control flow for 'parallel'") localError(n.info, "invalid control flow for 'parallel'")
# 'break' that leaves the 'parallel' section is not valid either # 'break' that leaves the 'parallel' section is not valid either
# or maybe we should generate a 'try' XXX # or maybe we should generate a 'try' XXX
of nkVarSection: of nkVarSection, nkLetSection:
for it in n: for it in n:
let value = it.lastSon 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: if value.kind != nkEmpty:
for j in 0 .. it.len-3: for j in 0 .. it.len-3:
if it[j].isLocal: if it[j].isLocal:
let slot = c.getSlot(it[j].sym) let slot = c.getSlot(it[j].sym)
if slot.lower.isNil: slot.lower = value if slot.lower.isNil: slot.lower = value
else: internalError(it.info, "slot already has a lower bound") 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 nkCaseStmt: analyseCase(c, n)
of nkIfStmt, nkIfExpr: analyseIf(c, n) of nkIfStmt, nkIfExpr: analyseIf(c, n)
of nkWhileStmt: of nkWhileStmt:
@ -396,7 +412,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
case n.kind case n.kind
of nkVarSection: of nkVarSection, nkLetSection:
result = nil result = nil
for it in n: for it in n:
let b = it.lastSon let b = it.lastSon
@ -464,6 +480,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
generateAliasChecks(a, result) generateAliasChecks(a, result)
result.add varSection result.add varSection
result.add callCodeGenProc("openBarrier", barrier) result.add callCodegenProc("openBarrier", barrier)
result.add transformSpawn(owner, body, 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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -57,30 +57,125 @@ discard """
c() c()
--> we need a stack of scopes for this analysis --> 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 type
TEffects = object TEffects = object
exc: PNode # stack of exceptions exc: PNode # stack of exceptions
tags: PNode # list of tags tags: PNode # list of tags
uses: PNode # list of used global variables bottom, inTryStmt: int
bottom: int
owner: PSym owner: PSym
init: seq[int] # list of initialized variables init: seq[int] # list of initialized variables
guards: TModel # nested guards guards: TModel # nested guards
locked: seq[PNode] # locked locations locked: seq[PNode] # locked locations
gcUnsafe, isRecursive: bool gcUnsafe, isRecursive, isToplevel: bool
maxLockLevel, currLockLevel: TLockLevel
PEffects = var TEffects 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 = proc isLocalVar(a: PEffects, s: PSym): bool =
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner 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 if n.kind != nkSym: return
let s = n.sym let s = n.sym
if isLocalVar(a, s): if isLocalVar(a, s):
if volatileCheck: makeVolatile(a, s)
for x in a.init: for x in a.init:
if x == s.id: return if x == s.id: return
a.init.add s.id a.init.add s.id
@ -91,14 +186,13 @@ proc initVarViaNew(a: PEffects, n: PNode) =
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}: if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
# 'x' is not nil, but that doesn't mean its "not nil" children # 'x' is not nil, but that doesn't mean its "not nil" children
# are initialized: # are initialized:
initVar(a, n) initVar(a, n, volatileCheck=true)
elif isLocalVar(a, s):
makeVolatile(a, s)
when trackGlobals: proc warnAboutGcUnsafe(n: PNode) =
proc addUse(a: PEffects, e: PNode) = #assert false
var aa = a.uses message(n.info, warnGcUnsafe, renderTree(n))
for i in 0 .. <aa.len:
if aa[i].sym.id == e.sym.id: return
a.uses.add(e)
proc useVar(a: PEffects, n: PNode) = proc useVar(a: PEffects, n: PNode) =
let s = n.sym let s = n.sym
@ -110,12 +204,11 @@ proc useVar(a: PEffects, n: PNode) =
message(n.info, warnUninit, s.name.s) message(n.info, warnUninit, s.name.s)
# prevent superfluous warnings about the same variable: # prevent superfluous warnings about the same variable:
a.init.add s.id a.init.add s.id
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar: if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
when trackGlobals: if s.guard != nil: guardGlobal(a, n, s.guard)
a.addUse(copyNode(n))
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
tfGcSafe notin s.typ.flags: tfGcSafe notin s.typ.flags:
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
a.gcUnsafe = true a.gcUnsafe = true
type type
@ -130,20 +223,27 @@ proc addToIntersection(inter: var TIntersection, s: int) =
proc throws(tracked, n: PNode) = proc throws(tracked, n: PNode) =
if n.typ == nil or n.typ.kind != tyError: tracked.add n 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 = proc excType(n: PNode): PType =
# reraise is like raising E_Base: # 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) result = skipTypes(t, skipPtrs)
proc createRaise(n: PNode): PNode = proc createRaise(n: PNode): PNode =
result = newNode(nkType) result = newNode(nkType)
result.typ = sysTypeFromName"E_Base" result.typ = getEbase()
if not n.isNil: result.info = n.info if not n.isNil: result.info = n.info
proc createTag(n: PNode): PNode = proc createTag(n: PNode): PNode =
result = newNode(nkType) 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 if not n.isNil: result.info = n.info
proc createAnyGlobal(n: PNode): PNode = proc createAnyGlobal(n: PNode): PNode =
@ -179,17 +279,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) =
else: else:
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil) 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) = proc listEffects(a: PEffects) =
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ)) 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.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) = proc catches(tracked: PEffects, e: PType) =
let e = skipTypes(e, skipPtrs) let e = skipTypes(e, skipPtrs)
@ -219,7 +313,9 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldState = tracked.init.len let oldState = tracked.init.len
var inter: TIntersection = @[] 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: for i in oldState.. <tracked.init.len:
addToIntersection(inter, tracked.init[i]) addToIntersection(inter, tracked.init[i])
@ -274,7 +370,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
# list the computed effects up to here: # list the computed effects up to here:
listEffects(tracked) listEffects(tracked)
proc effectSpec(n: PNode, effectType = wRaises): PNode = proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it.kind == nkExprColonExpr and whichPragma(it) == effectType: if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
@ -284,8 +380,7 @@ proc effectSpec(n: PNode, effectType = wRaises): PNode =
result.add(it.sons[1]) result.add(it.sons[1])
return return
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) = proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
var x = x
let spec = effectSpec(x, effectType) let spec = effectSpec(x, effectType)
if isNil(spec): if isNil(spec):
let s = n.sons[namePos].sym 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: # set the type so that the following analysis doesn't screw up:
effects.sons[i].typ = real[i].typ 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]) 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) = proc documentRaises*(n: PNode) =
if n.sons[namePos].kind != nkSym: return if n.sons[namePos].kind != nkSym: return
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects) let pragmas = n.sons[pragmasPos]
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects) 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 == {} 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. # when imported from C, we assume GC-safety.
result = n.kind == nkSym and sfImportc in n.sym.flags 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) = proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
let pragma = s.ast.sons[pragmasPos] let pragma = s.ast.sons[pragmasPos]
let spec = effectSpec(pragma, wRaises) let spec = effectSpec(pragma, wRaises)
@ -331,8 +447,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
mergeTags(tracked, tagSpec, n) mergeTags(tracked, tagSpec, n)
if notGcSafe(s.typ) and sfImportc notin s.flags: 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 tracked.gcUnsafe = true
mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
let n = n.skipConv 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) message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
of impYes: discard 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) = 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: if op != nil and op.kind == tyProc and n.kind != nkNilLit:
internalAssert op.n.sons[0].kind == nkEffectList internalAssert op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0] 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 # 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: # stated there are no additional effects, so simply propagate them:
propagateEffects(tracked, n, n.sym) propagateEffects(tracked, n, n.sym)
else: elif not isOwnedProcVar(a, tracked.owner):
# we have no explicit effects so assume the worst: # we have no explicit effects so assume the worst:
addEffect(tracked, createRaise(n)) assumeTheWorst(tracked, n, op)
addTag(tracked, createTag(n))
when trackGlobals: addUse(tracked, createAnyGlobal(n))
# assume GcUnsafe unless in its type; 'forward' does not matter: # assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op): if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true tracked.gcUnsafe = true
else: else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n)
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
if notGcSafe(op): if notGcSafe(op):
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true tracked.gcUnsafe = true
notNilCheck(tracked, n, paramType) notNilCheck(tracked, n, paramType)
@ -494,7 +622,8 @@ proc track(tracked: PEffects, n: PNode) =
useVar(tracked, n) useVar(tracked, n)
of nkRaiseStmt: of nkRaiseStmt:
n.sons[0].info = n.info 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): for i in 0 .. <safeLen(n):
track(tracked, n.sons[i]) track(tracked, n.sons[i])
of nkCallKinds: of nkCallKinds:
@ -506,8 +635,12 @@ proc track(tracked: PEffects, n: PNode) =
# are indistinguishable from normal procs (both have tyProc type) and # are indistinguishable from normal procs (both have tyProc type) and
# we can detect them only by checking for attached nkEffectList. # 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 op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
if a.kind == nkSym and a.sym == tracked.owner: if a.kind == nkSym:
tracked.isRecursive = true 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] var effectList = op.n.sons[0]
if a.kind == nkSym and a.sym.kind == skMethod: if a.kind == nkSym and a.sym.kind == skMethod:
propagateEffects(tracked, n, a.sym) propagateEffects(tracked, n, a.sym)
@ -515,18 +648,14 @@ proc track(tracked: PEffects, n: PNode) =
if isForwardedProc(a): if isForwardedProc(a):
propagateEffects(tracked, n, a.sym) propagateEffects(tracked, n, a.sym)
elif isIndirectCall(a, tracked.owner): elif isIndirectCall(a, tracked.owner):
addEffect(tracked, createRaise(n)) assumeTheWorst(tracked, n, op)
addTag(tracked, createTag(n))
when trackGlobals: addUse(tracked, createAnyGlobal(n))
# XXX handle 'gcsafe' properly for callbacks!
else: else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n)
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
if notGcSafe(op) and not importedFromC(a): if notGcSafe(op) and not importedFromC(a):
# and it's not a recursive call: # and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner): if not (a.kind == nkSym and a.sym == tracked.owner):
message(n.info, warnGcUnsafe, renderTree(n)) warnAboutGcUnsafe(n)
tracked.gcUnsafe = true tracked.gcUnsafe = true
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) 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}: 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]) initVarViaNew(tracked, n.sons[1])
for i in 0 .. <safeLen(n): for i in 0 .. <safeLen(n):
track(tracked, n.sons[i]) track(tracked, n.sons[i])
of nkDotExpr:
guardDotAccess(tracked, n)
for i in 0 .. <len(n): track(tracked, n.sons[i])
of nkCheckedFieldExpr: of nkCheckedFieldExpr:
track(tracked, n.sons[0]) track(tracked, n.sons[0])
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n) if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
@ -541,19 +673,19 @@ proc track(tracked: PEffects, n: PNode) =
of nkPragma: trackPragmaStmt(tracked, n) of nkPragma: trackPragmaStmt(tracked, n)
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
track(tracked, n.sons[1]) track(tracked, n.sons[1])
initVar(tracked, n.sons[0]) initVar(tracked, n.sons[0], volatileCheck=true)
invalidateFacts(tracked.guards, n.sons[0]) invalidateFacts(tracked.guards, n.sons[0])
track(tracked, n.sons[0]) track(tracked, n.sons[0])
addAsgnFact(tracked.guards, n.sons[0], n.sons[1]) addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
notNilCheck(tracked, n.sons[1], n.sons[0].typ) notNilCheck(tracked, n.sons[1], n.sons[0].typ)
when false: cstringCheck(tracked, n) when false: cstringCheck(tracked, n)
of nkVarSection: of nkVarSection, nkLetSection:
for child in n: for child in n:
let last = lastSon(child) let last = lastSon(child)
if child.kind == nkIdentDefs and last.kind != nkEmpty: if child.kind == nkIdentDefs and last.kind != nkEmpty:
track(tracked, last) track(tracked, last)
for i in 0 .. child.len-3: 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) addAsgnFact(tracked.guards, child.sons[i], last)
notNilCheck(tracked, last, child.sons[i].typ) notNilCheck(tracked, last, child.sons[i].typ)
# since 'var (a, b): T = ()' is not even allowed, there is always type # 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: if sfDiscriminant in x.sons[0].sym.flags:
addDiscriminantFact(tracked.guards, x) addDiscriminantFact(tracked.guards, x)
setLen(tracked.guards, oldFacts) 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, of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef: nkMacroDef, nkTemplateDef:
discard discard
@ -639,6 +781,16 @@ proc checkMethodEffects*(disp, branch: PSym) =
if sfThread in disp.flags and notGcSafe(branch.typ): if sfThread in disp.flags and notGcSafe(branch.typ):
localError(branch.info, "base method is GC-safe, but '$1' is not" % localError(branch.info, "base method is GC-safe, but '$1' is not" %
branch.name.s) 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) = proc setEffectsForProcType*(t: PType, n: PNode) =
var effects = t.n.sons[0] var effects = t.n.sons[0]
@ -659,14 +811,13 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
newSeq(effects.sons, effectListLen) newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info) effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info) effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
effects.sons[usesEffects] = newNodeI(nkArgList, s.info)
t.exc = effects.sons[exceptionEffects] t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects] t.tags = effects.sons[tagEffects]
t.uses = effects.sons[usesEffects]
t.owner = s t.owner = s
t.init = @[] t.init = @[]
t.guards = @[] t.guards = @[]
t.locked = @[]
proc trackProc*(s: PSym, body: PNode) = proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0] var effects = s.typ.n.sons[0]
@ -700,9 +851,17 @@ proc trackProc*(s: PSym, body: PNode) =
if optThreadAnalysis in gGlobalOptions: if optThreadAnalysis in gGlobalOptions:
if sfThread in s.flags and t.gcUnsafe: if sfThread in s.flags and t.gcUnsafe:
#localError(s.info, warnGcUnsafe2, s.name.s) if optThreads in gGlobalOptions:
localError(s.info, "'$1' is not GC-safe" % s.name.s) 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 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) = proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, 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 effects = newNode(nkEffectList, n.info)
var t: TEffects var t: TEffects
initEffects(effects, module, t) initEffects(effects, module, t)
t.isToplevel = true
track(t, n) track(t, n)

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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 nkIdent: s = lookUp(c, n.sons[0])
of nkSym: s = n.sons[0].sym of nkSym: s = n.sons[0].sym
else: illFormedAst(n) 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) var x = newSymNode(s)
x.info = n.info x.info = n.info
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
n.sons[0] = x n.sons[0] = x
suggestSym(x.info, s) suggestSym(x.info, s)
styleCheckUse(x.info, s)
else: else:
localError(n.info, errInvalidControlFlowX, s.name.s) localError(n.info, errInvalidControlFlowX, s.name.s)
else: else:
localError(n.info, errGenerated, "'continue' cannot have a label") 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, localError(n.info, errInvalidControlFlowX,
renderTree(n, {renderNoComments})) renderTree(n, {renderNoComments}))
@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode =
var covered: BiggestInt = 0 var covered: BiggestInt = 0
var typ = commonTypeBegin var typ = commonTypeBegin
var hasElse = false var hasElse = false
var notOrdinal = false
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
chckCovered = true chckCovered = true
of tyFloat..tyFloat128, tyString, tyError: of tyFloat..tyFloat128, tyString, tyError:
discard notOrdinal = true
else: else:
localError(n.info, errSelectorMustBeOfCertainTypes) localError(n.info, errSelectorMustBeOfCertainTypes)
return return
@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode =
hasElse = true hasElse = true
else: else:
illFormedAst(x) illFormedAst(x)
if notOrdinal and not hasElse:
message(n.info, warnDeprecated,
"use 'else: discard'; non-ordinal case without 'else'")
if chckCovered: if chckCovered:
if covered == toCover(n.sons[0].typ): if covered == toCover(n.sons[0].typ):
hasElse = true hasElse = true
@ -258,12 +263,13 @@ proc semTry(c: PContext, n: PNode): PNode =
n.sons[0] = semExprBranchScope(c, n.sons[0]) n.sons[0] = semExprBranchScope(c, n.sons[0])
typ = commonType(typ, n.sons[0].typ) typ = commonType(typ, n.sons[0].typ)
var check = initIntSet() 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] var a = n.sons[i]
checkMinSonsLen(a, 1) checkMinSonsLen(a, 1)
var length = sonsLen(a) var length = sonsLen(a)
if a.kind == nkExceptBranch: 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: if length == 2 and a.sons[0].kind == nkBracket:
a.sons[0..0] = a.sons[0].sons a.sons[0..0] = a.sons[0].sons
length = a.sonsLen length = a.sonsLen
@ -277,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode =
a.sons[j].typ = typ a.sons[j].typ = typ
if containsOrIncl(check, typ.id): if containsOrIncl(check, typ.id):
localError(a.sons[j].info, errExceptionAlreadyHandled) localError(a.sons[j].info, errExceptionAlreadyHandled)
elif a.kind != nkFinally: elif a.kind != nkFinally:
illFormedAst(n) illFormedAst(n)
# last child of an nkExcept/nkFinally branch is a statement: # last child of an nkExcept/nkFinally branch is a statement:
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1]) 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 dec c.p.inTryStmt
if isEmptyType(typ) or typ.kind == tyNil: if isEmptyType(typ) or typ.kind == tyNil:
discardCheck(c, n.sons[0]) discardCheck(c, n.sons[0])
@ -289,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode =
if typ == enforceVoidContext: if typ == enforceVoidContext:
result.typ = enforceVoidContext result.typ = enforceVoidContext
else: else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
n.sons[0] = fitNode(c, typ, n.sons[0]) 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] var it = n.sons[i]
let j = it.len-1 let j = it.len-1
it.sons[j] = fitNode(c, typ, it.sons[j]) it.sons[j] = fitNode(c, typ, it.sons[j])
result.typ = typ result.typ = typ
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n) result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
@ -323,6 +331,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
else: else:
result = semIdentWithPragma(c, kind, n, {}) result = semIdentWithPragma(c, kind, n, {})
suggestSym(n.info, result) suggestSym(n.info, result)
styleCheckDef(result)
proc checkNilable(v: PSym) = proc checkNilable(v: PSym) =
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: 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 var def: PNode
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
# BUGFIX: ``fitNode`` is needed here! if typ != nil:
# check type compability between def.typ and typ: if typ.isMetaType:
if typ != nil: def = fitNode(c, typ, def) 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: else:
typ = skipIntLit(def.typ) typ = skipIntLit(def.typ)
if typ.kind in {tySequence, tyArray, tySet} and if typ.kind in {tySequence, tyArray, tySet} and
@ -441,7 +456,7 @@ proc semConst(c: PContext, n: PNode): PNode =
if typ == nil: if typ == nil:
localError(a.sons[2].info, errConstExprExpected) localError(a.sons[2].info, errConstExprExpected)
continue continue
if not typeAllowed(typ, skConst): if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
localError(a.info, errXisNoType, typeToString(typ)) localError(a.info, errXisNoType, typeToString(typ))
continue continue
v.typ = typ v.typ = typ
@ -454,153 +469,7 @@ proc semConst(c: PContext, n: PNode): PNode =
addSon(b, copyTree(def)) addSon(b, copyTree(def))
addSon(result, b) addSon(result, b)
type include semfields
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
proc addForVarDecl(c: PContext, v: PSym) = proc addForVarDecl(c: PContext, v: PSym) =
if warnShadowIdent in gNotes: if warnShadowIdent in gNotes:
@ -614,6 +483,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
proc symForVar(c: PContext, n: PNode): PSym = proc symForVar(c: PContext, n: PNode): PSym =
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
result = newSymG(skForVar, m, c) result = newSymG(skForVar, m, c)
styleCheckDef(result)
proc semForVars(c: PContext, n: PNode): PNode = proc semForVars(c: PContext, n: PNode): PNode =
result = n result = n
@ -906,7 +776,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
if it.kind == nkExprColonExpr: if it.kind == nkExprColonExpr:
# pass pragma argument to the macro too: # pass pragma argument to the macro too:
x.add(it.sons[1]) 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: # recursion assures that this works for multiple macro annotations too:
return semStmt(c, x) return semStmt(c, x)
@ -934,6 +804,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
gp = newNodeI(nkGenericParams, n.info) gp = newNodeI(nkGenericParams, n.info)
if n.sons[paramsPos].kind != nkEmpty: 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) semParamList(c, n.sons[paramsPos], gp, s)
# paramsTypeCheck(c, s.typ) # paramsTypeCheck(c, s.typ)
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty: 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) = proc semOverride(c: PContext, s: PSym, n: PNode) =
case s.name.s.normalize 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": of "deepcopy":
if s.typ.len == 2 and if s.typ.len == 2 and
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ.sons[1], s.typ.sons[0]): sameType(s.typ.sons[1], s.typ.sons[0]):
# Note: we store the deepCopy in the base of the pointer to mitigate # Note: we store the deepCopy in the base of the pointer to mitigate
# the problem that pointers are structural types: # 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.kind in {tyObject, tyDistinct, tyEnum}:
if t.deepCopy.isNil: t.deepCopy = s if t.deepCopy.isNil: t.deepCopy = s
else: else:
@ -1036,6 +916,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
of "=": discard of "=": discard
else: localError(n.info, errGenerated, else: localError(n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'") "'destroy' or 'deepCopy' expected for 'override'")
incl(s.flags, sfUsed)
type type
TProcCompilationSteps = enum TProcCompilationSteps = enum
@ -1128,7 +1009,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pragma(c, s, n.sons[pragmasPos], validPragmas) pragma(c, s, n.sons[pragmasPos], validPragmas)
else: else:
implicitPragmas(c, s, n, validPragmas) implicitPragmas(c, s, n, validPragmas)
else: else:
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc) localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
if sfForward notin proto.flags: if sfForward notin proto.flags:
@ -1292,9 +1173,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
let pragmaList = n.sons[0] let pragmaList = n.sons[0]
pragma(c, nil, pragmaList, exprPragmas) pragma(c, nil, pragmaList, exprPragmas)
result = semExpr(c, n.sons[1]) result = semExpr(c, n.sons[1])
n.sons[1] = result
for i in 0 .. <pragmaList.len: for i in 0 .. <pragmaList.len:
if whichPragma(pragmaList.sons[i]) == wLine: case whichPragma(pragmaList.sons[i])
setLine(result, pragmaList.sons[i].info) 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 = proc semStaticStmt(c: PContext, n: PNode): PNode =
let a = semStmt(c, n.sons[0]) let a = semStmt(c, n.sons[0])
@ -1340,8 +1226,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# nkNilLit, nkEmpty}: # nkNilLit, nkEmpty}:
# dec last # dec last
for i in countup(0, length - 1): for i in countup(0, length - 1):
case n.sons[i].kind let k = n.sons[i].kind
of nkFinally, nkExceptBranch: case k
of nkFinally, nkExceptBranch, nkDefer:
# stand-alone finally and except blocks are # stand-alone finally and except blocks are
# transformed into regular try blocks: # transformed into regular try blocks:
# #
@ -1350,14 +1237,27 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# ... | ... # ... | ...
# | finally: # | finally:
# | fclose(f) # | 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 tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
var body = newNodeI(nkStmtList, n.sons[i].info) var body = newNodeI(nkStmtList, n.sons[i].info)
if i < n.sonsLen - 1: if i < n.sonsLen - 1:
body.sons = n.sons[(i+1)..(-1)] body.sons = n.sons[(i+1)..(-1)]
tryStmt.addSon(body) tryStmt.addSon(body)
tryStmt.addSon(n.sons[i]) tryStmt.addSon(deferPart)
n.sons[i] = semTry(c, tryStmt) n.sons[i] = semTry(c, tryStmt)
n.sons.setLen(i+1) n.sons.setLen(i+1)
n.typ = n.sons[i].typ
return return
else: else:
n.sons[i] = semExpr(c, n.sons[i]) n.sons[i] = semExpr(c, n.sons[i])
@ -1393,11 +1293,16 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: discard else: discard
if result.len == 1: if result.len == 1:
result = result.sons[0] 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: when false:
# a statement list (s; e) has the type 'e': # a statement list (s; e) has the type 'e':
if result.kind == nkStmtList and result.len > 0: if result.kind == nkStmtList and result.len > 0:
var lastStmt = lastSon(result) var lastStmt = lastSon(result)
if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt): if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
result.typ = lastStmt.typ result.typ = lastStmt.typ
#localError(lastStmt.info, errGenerated, #localError(lastStmt.info, errGenerated,
# "Last expression must be explicitly returned if it " & # "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 # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -63,7 +63,8 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
else: else:
# semantic checking requires a type; ``fitNode`` deals with it # semantic checking requires a type; ``fitNode`` deals with it
# appropriately # 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)) result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n) a = initOverloadIter(o, c, n)
while a != nil: while a != nil:
@ -71,7 +72,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
addSon(result, newSymNode(a, n.info)) addSon(result, newSymNode(a, n.info))
a = nextOverloadIter(o, c, n) 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: for i in 0 .. < n.len:
var a = n.sons[i] var a = n.sons[i]
# If 'a' is an overloaded symbol, we used to use the first symbol # 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) illFormedAst(a)
result = newNodeI(nkEmpty, n.info) 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: for i in 0 .. < n.len:
toMixin.incl(considerQuotedIdent(n.sons[i]).id) toMixin.incl(considerQuotedIdent(n.sons[i]).id)
result = newNodeI(nkEmpty, n.info) result = newNodeI(nkEmpty, n.info)
@ -106,7 +107,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
type type
TemplCtx {.pure, final.} = object TemplCtx {.pure, final.} = object
c: PContext c: PContext
toBind, toMixin, toInject: TIntSet toBind, toMixin, toInject: IntSet
owner: PSym owner: PSym
proc getIdentNode(c: var TemplCtx, n: PNode): PNode = 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: if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else: else:
for i in 0 .. <n.safeLen: for i in 0 .. <n.safeLen:
result.sons[i] = onlyReplaceParams(c, n.sons[i]) 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): if not isTemplParam(c, ident):
let local = newGenSym(k, ident, c) let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local) addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
replaceIdentBySym(n, newSymNode(local, n.info)) replaceIdentBySym(n, newSymNode(local, n.info))
else: else:
replaceIdentBySym(n, ident) replaceIdentBySym(n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed) 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 case s.kind
of skUnknown: of skUnknown:
# Introduced in this pass! Leave it as an identifier. # 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) result = newSymNodeTypeDesc(s, n.info)
else: else:
result = n result = n
else: result = newSymNode(s, n.info) else:
result = newSymNode(s, n.info)
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
result = n 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): if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else: else:
for i in countup(0, safeLen(n) - 1): for i in countup(0, safeLen(n) - 1):
result.sons[i] = semRoutineInTemplName(c, n.sons[i]) 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) var s = newGenSym(k, ident, c)
s.ast = n s.ast = n
addPrelimDecl(c.c, s) addPrelimDecl(c.c, s)
styleCheckDef(n.info, s)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info) n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
else: else:
n.sons[namePos] = ident 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: if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
elif contains(c.toBind, s.id): elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed) result = symChoice(c.c, n, s, scClosed)
elif contains(c.toMixin, s.name.id): elif contains(c.toMixin, s.name.id):
@ -270,6 +279,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# var yz: T # var yz: T
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s)
else: else:
result = semTemplSymbol(c.c, n, s) result = semTemplSymbol(c.c, n, s)
of nkBind: of nkBind:
@ -322,6 +332,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# labels are always 'gensym'ed: # labels are always 'gensym'ed:
let s = newGenSym(skLabel, n.sons[0], c) let s = newGenSym(skLabel, n.sons[0], c)
addPrelimDecl(c.c, s) addPrelimDecl(c.c, s)
styleCheckDef(s)
n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[0] = newSymNode(s, n.sons[0].info)
n.sons[1] = semTemplBody(c, n.sons[1]) n.sons[1] = semTemplBody(c, n.sons[1])
closeScope(c) closeScope(c)
@ -456,6 +467,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
incl(s.flags, sfGlobal) incl(s.flags, sfGlobal)
else: else:
s = semIdentVis(c, skTemplate, n.sons[0], {}) s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(s)
# check parameter list: # check parameter list:
s.scope = c.currentScope s.scope = c.currentScope
pushOwner(s) pushOwner(s)
@ -527,6 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# semtypes.addParamOrResult). Within the pattern we have to ensure # semtypes.addParamOrResult). Within the pattern we have to ensure
# to use the param with the proper type though: # to use the param with the proper type though:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
styleCheckUse(n.info, s)
let x = c.owner.typ.n.sons[s.position+1].sym let x = c.owner.typ.n.sons[s.position+1].sym
assert x.name == s.name assert x.name == s.name
result = newSymNode(x, n.info) result = newSymNode(x, n.info)

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2014 Andreas Rumpf # (c) Copyright 2014 Andreas Rumpf
# #
# See the file "copying.txt", included in this # 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.typ = replaceTypeVarsT(cl, s.typ)
result.ast = replaceTypeVarsN(cl, s.ast) 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)) result = PType(idTableGet(cl.typeMap, t))
if result == nil: if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return 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)) var newbody = replaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags result.flags = result.flags + newbody.flags - tfInstClearedFlags
newbody.callConv = body.callConv # 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. # This type may be a generic alias and we want to resolve it here.
# One step is enough, because the recursive nature of # One step is enough, because the recursive nature of
# handleGenericInvokation will handle the alias-to-alias-to-alias case # handleGenericInvokation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody) rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, 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) = 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: if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
t.sons[0] = nil t.sons[0] = nil

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -25,39 +25,17 @@ var
lastCaasCmd* = "" lastCaasCmd* = ""
# in caas mode, the list of defines and options will be given at start-up? # 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? # 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) = proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd) var p = parseopt.initOptParser(cmd)
var argsCount = 0 var argsCount = 0
while true: while true:
parseopt.next(p) parseopt.next(p)
case p.kind case p.kind
of cmdEnd: break of cmdEnd: break
of cmdLongoption, cmdShortOption: of cmdLongoption, cmdShortOption: processSwitch(pass, p)
# 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 cmdArgument: of cmdArgument:
if argsCount == 0: if processArgument(pass, p, argsCount): break
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 pass == passCmd2: if pass == passCmd2:
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
rawMessage(errArgsNeedRunOption, []) rawMessage(errArgsNeedRunOption, [])
@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) =
of "tcp", "": of "tcp", "":
when useCaas: when useCaas:
var server = socket() var server = socket()
if server == invalidSocket: osError(osLastError()) if server == invalidSocket: raiseOSError(osLastError())
let p = getConfigVar("server.port") 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")) server.bindAddr(port, getConfigVar("server.address"))
var inp = "".TaintedString var inp = "".TaintedString
server.listen() server.listen()

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -12,7 +12,8 @@
import import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, 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): when not defined(noDocgen):
import docgen import docgen
@ -21,7 +22,8 @@ type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object CandidateErrors* = seq[PSym]
TCandidate* = object
c*: PContext c*: PContext
exactMatches*: int # also misused to prefer iters over procs exactMatches*: int # also misused to prefer iters over procs
genericMatches: int # also misused to prefer constraints genericMatches: int # also misused to prefer constraints
@ -44,7 +46,7 @@ type
# a distrinct type # a distrinct type
typedescMatched: bool typedescMatched: bool
inheritancePenalty: int # to prefer closest father object type 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 # user if overload resolution fails
TTypeRelation* = enum # order is important! TTypeRelation* = enum # order is important!
@ -201,16 +203,17 @@ proc writeMatches*(c: TCandidate) =
writeln(stdout, "intconv matches: " & $c.intConvMatches) writeln(stdout, "intconv matches: " & $c.intConvMatches)
writeln(stdout, "generic matches: " & $c.genericMatches) writeln(stdout, "generic matches: " & $c.genericMatches)
proc argTypeToString(arg: PNode): string = proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
if arg.kind in nkSymChoices: if arg.kind in nkSymChoices:
result = typeToString(arg[0].typ) result = typeToString(arg[0].typ, prefer)
for i in 1 .. <arg.len: for i in 1 .. <arg.len:
result.add(" | ") result.add(" | ")
result.add typeToString(arg[i].typ) result.add typeToString(arg[i].typ, prefer)
else: 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 = "" result = ""
for i in countup(startIdx, n.len - 1): for i in countup(startIdx, n.len - 1):
var arg = n.sons[i] 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]) arg = c.semOperand(c, n.sons[i])
n.sons[i] = arg n.sons[i] = arg
if arg.typ.kind == tyError: return if arg.typ.kind == tyError: return
add(result, argTypeToString(arg)) add(result, argTypeToString(arg, prefer))
if i != sonsLen(n) - 1: add(result, ", ") if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation 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? addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
of tyNil: of tyNil:
result = nil # what should it be? result = nil # what should it be?
of tySequence, tySet:
if t.sons[0].kind == tyEmpty: result = nil
else: result = t
of tyGenericParam, tyAnything: of tyGenericParam, tyAnything:
result = t result = t
while true: while true:
@ -343,7 +349,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
var y = a.n.sons[i].sym var y = a.n.sons[i].sym
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype: if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
return isNone 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.} = proc allowsNil(f: PType): TTypeRelation {.inline.} =
result = if tfNotNil notin f.flags: isSubtype else: isNone result = if tfNotNil notin f.flags: isSubtype else: isNone
@ -479,8 +485,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
dummyParam.typ = dummyType dummyParam.typ = dummyType
addDecl(c, dummyParam) addDecl(c, dummyParam)
var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false) var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
m.errors = bufferedMsgs #m.errors = bufferedMsgs
clearBufferedMsgs() clearBufferedMsgs()
if checkedBody == nil: return isNone if checkedBody == nil: return isNone
@ -930,6 +936,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else: else:
if f.sonsLen > 0 and f.sons[0].kind != tyNone: if f.sonsLen > 0 and f.sons[0].kind != tyNone:
result = typeRel(c, f.lastSon, a) 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: else:
result = isGeneric result = isGeneric
@ -1073,6 +1083,11 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode = arg: PNode): PNode =
# arg.typ can be nil in 'suggest': # arg.typ can be nil in 'suggest':
if isNil(arg.typ): return nil 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) var call = newNodeI(nkCall, arg.info)
call.add(f.n.copyTree) call.add(f.n.copyTree)
call.add(arg.copyTree) call.add(arg.copyTree)
@ -1143,8 +1158,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
of isEqual: inc(m.exactMatches) of isEqual: inc(m.exactMatches)
of isNone: discard of isNone: discard
if f.kind == tyStmt and argOrig.kind == nkDo: if f.kind == tyStmt:
return argOrig[bodyPos] return arg
elif f.kind == tyTypeDesc: elif f.kind == tyTypeDesc:
return arg return arg
elif f.kind == tyStatic: elif f.kind == tyStatic:
@ -1272,6 +1287,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
else: else:
# only one valid interpretation found: # only one valid interpretation found:
markUsed(arg.info, arg.sons[best].sym) 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], result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
@ -1319,7 +1335,7 @@ proc incrIndexType(t: PType) =
inc t.sons[0].n.sons[1].intVal inc t.sons[0].n.sons[1].intVal
proc matchesAux(c: PContext, n, nOrig: PNode, 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.} = template checkConstraint(n: expr) {.immediate, dirty.} =
if not formal.constraint.isNil: if not formal.constraint.isNil:
if matchNodeKinds(formal.constraint, n): if matchNodeKinds(formal.constraint, n):
@ -1480,8 +1496,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
# instantiate generic converters for that # instantiate generic converters for that
result = res != nil 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 include suggest
when not declared(tests):
template tests(s: stmt) {.immediate.} = discard
tests: tests:
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) 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 # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -11,7 +11,7 @@
# included from sigmatch.nim # included from sigmatch.nim
import algorithm, sequtils, pretty import algorithm, sequtils
const const
sep = '\t' sep = '\t'
@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) =
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
suggestSym(info, s) suggestSym(info, s)
if gCmd == cmdPretty: checkUse(info, s)
proc useSym*(sym: PSym): PNode = proc useSym*(sym: PSym): PNode =
result = newSymNode(sym) result = newSymNode(sym)

View file

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

View file

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

View file

@ -1,6 +1,6 @@
# #
# #
# The Nimrod Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2012 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
@ -117,7 +117,9 @@ proc isDeepConstExpr*(n: PNode): bool =
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure: of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
for i in 0 .. <n.len: for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false 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 else: discard
proc flattenTreeAux(d, a: PNode, op: TMagic) = proc flattenTreeAux(d, a: PNode, op: TMagic) =

View file

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

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