Merge branch 'devel'
Conflicts: compiler/nversion.nim
This commit is contained in:
commit
647aadc1ea
624 changed files with 28569 additions and 20584 deletions
19
build.sh
Normal file
19
build.sh
Normal 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
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -16,9 +16,9 @@ type
|
|||
TAnalysisResult* = enum
|
||||
arNo, arMaybe, arYes
|
||||
|
||||
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult
|
||||
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
|
||||
|
||||
proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||
proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
|
|
@ -39,7 +39,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
|
|||
result = isPartOfAux(n.sym.typ, b, marker)
|
||||
else: internalError(n.info, "isPartOfAux()")
|
||||
|
||||
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||
result = arNo
|
||||
if a == nil or b == nil: return
|
||||
if containsOrIncl(marker, a.id): return
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ type
|
|||
nkConstDef, # a const definition
|
||||
nkTypeDef, # a type definition
|
||||
nkYieldStmt, # the yield statement as a tree
|
||||
nkDefer, # the 'defer' statement
|
||||
nkTryStmt, # a try statement
|
||||
nkFinally, # a finally section
|
||||
nkRaiseStmt, # a raise statement
|
||||
|
|
@ -293,6 +294,7 @@ const
|
|||
# require RC ops
|
||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||
|
||||
const
|
||||
# getting ready for the future expr/stmt merge
|
||||
|
|
@ -566,8 +568,8 @@ type
|
|||
mBool, mChar, mString, mCstring,
|
||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
|
||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||
mIsMainModule, mCompileDate, mCompileTime, mProcCall,
|
||||
mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||
mNaN, mInf, mNegInf,
|
||||
mCompileOption, mCompileOptionArg,
|
||||
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
||||
|
|
@ -610,7 +612,7 @@ const
|
|||
# thus cannot be overloaded (also documented in the spec!):
|
||||
SpecialSemMagics* = {
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn}
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
|
||||
type
|
||||
PNode* = ref TNode
|
||||
|
|
@ -681,7 +683,6 @@ type
|
|||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||
# owns this location (required by GC algorithms
|
||||
# employing heap snapshots or sliding views)
|
||||
a*: int
|
||||
|
||||
# ---------------- end of backend information ------------------------------
|
||||
|
||||
|
|
@ -734,7 +735,7 @@ type
|
|||
# check for the owner when touching 'usedGenerics'.
|
||||
usedGenerics*: seq[PInstantiation]
|
||||
tab*: TStrTable # interface table for modules
|
||||
of skLet, skVar, skField:
|
||||
of skLet, skVar, skField, skForVar:
|
||||
guard*: PSym
|
||||
else: nil
|
||||
magic*: TMagic
|
||||
|
|
@ -772,6 +773,7 @@ type
|
|||
# it won't cause problems
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TLockLevel* = distinct int16
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
# types are identical iff they have the
|
||||
# same id; there may be multiple copies of a type
|
||||
|
|
@ -798,11 +800,12 @@ type
|
|||
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||
size*: BiggestInt # the size of the type in bytes
|
||||
# -1 means that the size is unkwown
|
||||
align*: int # the type's alignment requirements
|
||||
align*: int16 # the type's alignment requirements
|
||||
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||
loc*: TLoc
|
||||
|
||||
TPair*{.final.} = object
|
||||
key*, val*: PObject
|
||||
key*, val*: RootRef
|
||||
|
||||
TPairSeq* = seq[TPair]
|
||||
TTable*{.final.} = object # the same as table[PObject] of PObject
|
||||
|
|
@ -811,7 +814,7 @@ type
|
|||
|
||||
TIdPair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: PObject
|
||||
val*: RootRef
|
||||
|
||||
TIdPairSeq* = seq[TIdPair]
|
||||
TIdTable*{.final.} = object # the same as table[PIdent] of PObject
|
||||
|
|
@ -838,7 +841,7 @@ type
|
|||
counter*: int
|
||||
data*: TNodePairSeq
|
||||
|
||||
TObjectSeq* = seq[PObject]
|
||||
TObjectSeq* = seq[RootRef]
|
||||
TObjectSet*{.final.} = object
|
||||
counter*: int
|
||||
data*: TObjectSeq
|
||||
|
|
@ -1054,7 +1057,7 @@ proc discardSons(father: PNode) =
|
|||
father.sons = nil
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = 310841 # 612794
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
|
|
@ -1166,6 +1169,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
|||
result.sons = @[name, pattern, genericParams, params,
|
||||
pragmas, exceptions, body]
|
||||
|
||||
const
|
||||
UnspecifiedLockLevel* = TLockLevel(-1'i16)
|
||||
MaxLockLevel* = 1000'i16
|
||||
UnknownLockLevel* = TLockLevel(1001'i16)
|
||||
|
||||
proc `$`*(x: TLockLevel): string =
|
||||
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
|
||||
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
|
||||
else: result = $int16(x)
|
||||
|
||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
|
|
@ -1173,6 +1186,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
|
|||
result.size = - 1
|
||||
result.align = 2 # default alignment
|
||||
result.id = getID()
|
||||
result.lockLevel = UnspecifiedLockLevel
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
|
|
@ -1184,7 +1198,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
|||
a.flags = a.flags + b.flags
|
||||
if a.t == nil: a.t = b.t
|
||||
if a.r == nil: a.r = b.r
|
||||
if a.a == 0: a.a = b.a
|
||||
#if a.a == 0: a.a = b.a
|
||||
|
||||
proc assignType(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
|
|
@ -1195,6 +1209,7 @@ proc assignType(dest, src: PType) =
|
|||
dest.align = src.align
|
||||
dest.destructor = src.destructor
|
||||
dest.deepCopy = src.deepCopy
|
||||
dest.lockLevel = src.lockLevel
|
||||
# this fixes 'type TLock = TSysLock':
|
||||
if src.sym != nil:
|
||||
if dest.sym != nil:
|
||||
|
|
@ -1545,3 +1560,9 @@ proc isEmptyType*(t: PType): bool {.inline.} =
|
|||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||
|
||||
proc makeStmtList*(n: PNode): PNode =
|
||||
if n.kind == nkStmtList:
|
||||
result = n
|
||||
else:
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add n
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
import
|
||||
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
|
||||
|
||||
proc hashNode*(p: PObject): THash
|
||||
proc hashNode*(p: RootRef): THash
|
||||
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
|
||||
# Convert a tree into its YAML representation; this is used by the
|
||||
# YAML code generator and it is invaluable for debugging purposes.
|
||||
|
|
@ -24,21 +24,21 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
|
|||
proc lineInfoToStr*(info: TLineInfo): PRope
|
||||
|
||||
# ----------------------- node sets: ---------------------------------------
|
||||
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
|
||||
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
|
||||
# returns true whether n is in t
|
||||
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
|
||||
proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
|
||||
# include an element n in the table t
|
||||
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
|
||||
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
|
||||
# more are not needed ...
|
||||
|
||||
# ----------------------- (key, val)-Hashtables ----------------------------
|
||||
proc tablePut*(t: var TTable, key, val: PObject)
|
||||
proc tableGet*(t: TTable, key: PObject): PObject
|
||||
proc tablePut*(t: var TTable, key, val: RootRef)
|
||||
proc tableGet*(t: TTable, key: RootRef): RootRef
|
||||
type
|
||||
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
|
||||
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
|
||||
|
||||
proc tableSearch*(t: TTable, key, closure: PObject,
|
||||
comparator: TCmpProc): PObject
|
||||
proc tableSearch*(t: TTable, key, closure: RootRef,
|
||||
comparator: TCmpProc): RootRef
|
||||
# return val as soon as comparator returns true; if this never happens,
|
||||
# nil is returned
|
||||
|
||||
|
|
@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.}
|
|||
proc debug*(n: PNode) {.deprecated.}
|
||||
|
||||
# --------------------------- ident tables ----------------------------------
|
||||
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
|
||||
proc idTableGet*(t: TIdTable, key: int): PObject
|
||||
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
|
||||
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
|
||||
proc idTableGet*(t: TIdTable, key: int): RootRef
|
||||
proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
|
||||
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
|
||||
# checks if `t` contains the `key` (compared by the pointer value, not only
|
||||
# `key`'s id)
|
||||
|
|
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
|||
else: internalError(list.info, "getSymFromList")
|
||||
result = nil
|
||||
|
||||
proc hashNode(p: PObject): THash =
|
||||
proc hashNode(p: RootRef): THash =
|
||||
result = hash(cast[pointer](p))
|
||||
|
||||
proc mustRehash(length, counter: int): bool =
|
||||
|
|
@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope =
|
|||
toRope(toLinenumber(info)),
|
||||
toRope(toColumn(info))])
|
||||
|
||||
proc treeToYamlAux(n: PNode, marker: var TIntSet,
|
||||
proc treeToYamlAux(n: PNode, marker: var IntSet,
|
||||
indent, maxRecDepth: int): PRope
|
||||
proc symToYamlAux(n: PSym, marker: var TIntSet,
|
||||
proc symToYamlAux(n: PSym, marker: var IntSet,
|
||||
indent, maxRecDepth: int): PRope
|
||||
proc typeToYamlAux(n: PType, marker: var TIntSet,
|
||||
proc typeToYamlAux(n: PType, marker: var IntSet,
|
||||
indent, maxRecDepth: int): PRope
|
||||
proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
|
||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
var istr = spaces(indent + 2)
|
||||
result = toRope("[")
|
||||
|
|
@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
|||
inc(i, 2)
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
|
||||
proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
||||
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
|
||||
result = ropeConstr(indent, [toRope("kind"),
|
||||
|
|
@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
|||
flagsToStr(n.options), toRope("position"),
|
||||
toRope(n.position)])
|
||||
|
||||
proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
||||
proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif containsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
if sonsLen(n) > 0:
|
||||
result = toRope("[")
|
||||
|
|
@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
|||
toRope("align"), toRope(n.align),
|
||||
toRope("sons"), result])
|
||||
|
||||
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
||||
proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
|
|
@ -450,9 +450,10 @@ proc debug(n: PSym) =
|
|||
writeln(stdout, "skUnknown")
|
||||
else:
|
||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
|
||||
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
||||
flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
|
||||
writeln(stdout, "$1_$2: $3, $4, $5, $6" % [
|
||||
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
|
||||
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
|
||||
$n.kind])
|
||||
|
||||
proc debug(n: PType) =
|
||||
writeln(stdout, ropeToStr(debugType(n)))
|
||||
|
|
@ -469,7 +470,7 @@ proc nextTry(h, maxHash: THash): THash =
|
|||
# generates each int in range(maxHash) exactly once (see any text on
|
||||
# random-number generation for proof).
|
||||
|
||||
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
||||
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
|
||||
# returns true whether n is in t
|
||||
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
|
||||
while t.data[h] != nil:
|
||||
|
|
@ -478,7 +479,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
|||
h = nextTry(h, high(t.data))
|
||||
result = false
|
||||
|
||||
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
|
||||
proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
|
||||
var h: THash = hashNode(obj) and high(data)
|
||||
while data[h] != nil:
|
||||
assert(data[h] != obj)
|
||||
|
|
@ -493,12 +494,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
|
|||
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
|
||||
swap(t.data, n)
|
||||
|
||||
proc objectSetIncl(t: var TObjectSet, obj: PObject) =
|
||||
proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
|
||||
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
|
||||
objectSetRawInsert(t.data, obj)
|
||||
inc(t.counter)
|
||||
|
||||
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
||||
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
|
||||
# returns true if obj is already in the string table:
|
||||
var h: THash = hashNode(obj) and high(t.data)
|
||||
while true:
|
||||
|
|
@ -516,7 +517,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
|||
inc(t.counter)
|
||||
result = false
|
||||
|
||||
proc tableRawGet(t: TTable, key: PObject): int =
|
||||
proc tableRawGet(t: TTable, key: RootRef): int =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key == key:
|
||||
|
|
@ -524,8 +525,8 @@ proc tableRawGet(t: TTable, key: PObject): int =
|
|||
h = nextTry(h, high(t.data))
|
||||
result = -1
|
||||
|
||||
proc tableSearch(t: TTable, key, closure: PObject,
|
||||
comparator: TCmpProc): PObject =
|
||||
proc tableSearch(t: TTable, key, closure: RootRef,
|
||||
comparator: TCmpProc): RootRef =
|
||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||
while t.data[h].key != nil:
|
||||
if t.data[h].key == key:
|
||||
|
|
@ -535,12 +536,12 @@ proc tableSearch(t: TTable, key, closure: PObject,
|
|||
h = nextTry(h, high(t.data))
|
||||
result = nil
|
||||
|
||||
proc tableGet(t: TTable, key: PObject): PObject =
|
||||
proc tableGet(t: TTable, key: RootRef): RootRef =
|
||||
var index = tableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
|
||||
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
|
||||
var h: THash = hashNode(key) and high(data)
|
||||
while data[h].key != nil:
|
||||
assert(data[h].key != key)
|
||||
|
|
@ -556,7 +557,7 @@ proc tableEnlarge(t: var TTable) =
|
|||
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||
swap(t.data, n)
|
||||
|
||||
proc tablePut(t: var TTable, key, val: PObject) =
|
||||
proc tablePut(t: var TTable, key, val: RootRef) =
|
||||
var index = tableRawGet(t, key)
|
||||
if index >= 0:
|
||||
t.data[index].val = val
|
||||
|
|
@ -626,20 +627,34 @@ proc strTableAdd(t: var TStrTable, n: PSym) =
|
|||
strTableRawInsert(t.data, n)
|
||||
inc(t.counter)
|
||||
|
||||
proc reallySameIdent(a, b: string): bool {.inline.} =
|
||||
when defined(nimfix):
|
||||
result = a[0] == b[0]
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||
# returns true if n is already in the string table:
|
||||
# It is essential that `n` is written nevertheless!
|
||||
# This way the newest redefinition is picked by the semantic analyses!
|
||||
assert n.name != nil
|
||||
var h: THash = n.name.h and high(t.data)
|
||||
var replaceSlot = -1
|
||||
while true:
|
||||
var it = t.data[h]
|
||||
if it == nil: break
|
||||
if it.name.id == n.name.id:
|
||||
t.data[h] = n # overwrite it with newer definition!
|
||||
return true # found it
|
||||
# Semantic checking can happen multiple times thanks to templates
|
||||
# and overloading: (var x=@[]; x).mapIt(it).
|
||||
# So it is possible the very same sym is added multiple
|
||||
# times to the symbol table which we allow here with the 'it == n' check.
|
||||
if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s):
|
||||
if it == n: return false
|
||||
replaceSlot = h
|
||||
h = nextTry(h, high(t.data))
|
||||
if mustRehash(len(t.data), t.counter):
|
||||
if replaceSlot >= 0:
|
||||
t.data[replaceSlot] = n # overwrite it with newer definition!
|
||||
return true # found it
|
||||
elif mustRehash(len(t.data), t.counter):
|
||||
strTableEnlarge(t)
|
||||
strTableRawInsert(t.data, n)
|
||||
else:
|
||||
|
|
@ -677,7 +692,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
|||
ti.h = nextTry(h, high(tab.data))
|
||||
|
||||
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
excluding: TIntSet): PSym =
|
||||
excluding: IntSet): PSym =
|
||||
var h: THash = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
|
|
@ -693,7 +708,7 @@ proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
|||
if result != nil and contains(excluding, result.id): result = nil
|
||||
|
||||
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
||||
excluding: TIntSet): PSym =
|
||||
excluding: IntSet): PSym =
|
||||
ti.h = s.h
|
||||
ti.name = s
|
||||
if tab.counter == 0: result = nil
|
||||
|
|
@ -740,22 +755,22 @@ proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
|
|||
if index >= 0: result = t.data[index].key == key
|
||||
else: result = false
|
||||
|
||||
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
|
||||
proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
|
||||
var index = idTableRawGet(t, key.id)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
proc idTableGet(t: TIdTable, key: int): PObject =
|
||||
proc idTableGet(t: TIdTable, key: int): RootRef =
|
||||
var index = idTableRawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = nil
|
||||
|
||||
iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
|
||||
iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
|
||||
for i in 0..high(t.data):
|
||||
if t.data[i].key != nil:
|
||||
yield (t.data[i].key.id, t.data[i].val)
|
||||
|
||||
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
|
||||
var h: THash
|
||||
h = key.id and high(data)
|
||||
while data[h].key != nil:
|
||||
|
|
@ -765,7 +780,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
|||
data[h].key = key
|
||||
data[h].val = val
|
||||
|
||||
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
||||
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
|
||||
var
|
||||
index: int
|
||||
n: TIdPairSeq
|
||||
|
|
@ -784,7 +799,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
|||
idTableRawInsert(t.data, key, val)
|
||||
inc(t.counter)
|
||||
|
||||
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
|
||||
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
|
||||
for i in 0 .. high(t.data):
|
||||
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# this unit handles Nimrod sets; it implements bit sets
|
||||
# the code here should be reused in the Nimrod standard library
|
||||
# this unit handles Nim sets; it implements bit sets
|
||||
# the code here should be reused in the Nim standard library
|
||||
|
||||
type
|
||||
TBitSet* = seq[int8] # we use byte here to avoid issues with
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -370,7 +370,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
# we used to attempt to save space here by only storing a dummy AST if
|
||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
||||
# it is not necessary, but Nim's heavy compile-time evaluation features
|
||||
# make that unfeasible nowadays:
|
||||
encodeNode(w, s.info, s.ast, result)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -103,9 +103,9 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
|||
result = ropef("$1, $1Len0", [rdLoc(a)])
|
||||
of tyString, tySequence:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField()])
|
||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
||||
else:
|
||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
|
||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
||||
of tyArray, tyArrayConstr:
|
||||
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
|
||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -11,11 +11,19 @@
|
|||
|
||||
# -------------------------- constant expressions ------------------------
|
||||
|
||||
proc int64Literal(i: BiggestInt): PRope =
|
||||
if i > low(int64):
|
||||
result = rfmt(nil, "IL64($1)", toRope(i))
|
||||
else:
|
||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
|
||||
|
||||
proc intLiteral(i: BiggestInt): PRope =
|
||||
if (i > low(int32)) and (i <= high(int32)):
|
||||
if i > low(int32) and i <= high(int32):
|
||||
result = toRope(i)
|
||||
elif i == low(int32):
|
||||
# Nimrod has the same bug for the same reasons :-)
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result = ~"(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result = rfmt(nil, "IL64($1)", toRope(i))
|
||||
|
|
@ -31,7 +39,7 @@ proc int32Literal(i: int): PRope =
|
|||
proc genHexLiteral(v: PNode): PRope =
|
||||
# hex literals are unsigned in C
|
||||
# so we don't generate hex literals any longer.
|
||||
if not (v.kind in {nkIntLit..nkUInt64Lit}):
|
||||
if v.kind notin {nkIntLit..nkUInt64Lit}:
|
||||
internalError(v.info, "genHexLiteral")
|
||||
result = intLiteral(v.intVal)
|
||||
|
||||
|
|
@ -46,16 +54,18 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
|||
case n.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case skipTypes(ty, abstractVarRange).kind
|
||||
of tyChar, tyInt64, tyNil:
|
||||
of tyChar, tyNil:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyInt:
|
||||
if (n.intVal >= low(int32)) and (n.intVal <= high(int32)):
|
||||
if n.intVal >= low(int32) and n.intVal <= high(int32):
|
||||
result = int32Literal(int32(n.intVal))
|
||||
else:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyBool:
|
||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||
else: result = ~"NIM_FALSE"
|
||||
of tyInt64: result = int64Literal(n.intVal)
|
||||
of tyUInt64: result = uint64Literal(uint64(n.intVal))
|
||||
else:
|
||||
result = ropef("(($1) $2)", [getTypeDesc(p.module,
|
||||
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
|
||||
|
|
@ -214,9 +224,9 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
|
|||
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
flags + { needToCopy }
|
||||
flags + {needToCopy}
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - { needToCopy }
|
||||
flags - {needToCopy}
|
||||
else:
|
||||
flags
|
||||
for i in 0 .. <dest.t.len:
|
||||
|
|
@ -230,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
|||
if t == nil: return
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
flags + { needToCopy }
|
||||
flags + {needToCopy}
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - { needToCopy }
|
||||
flags - {needToCopy}
|
||||
else:
|
||||
flags
|
||||
case t.kind
|
||||
|
|
@ -318,7 +328,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
|||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||
of tyObject:
|
||||
# XXX: check for subtyping?
|
||||
if needsComplexAssignment(ty):
|
||||
if not isObjLackingTypeField(ty):
|
||||
genGenericAsgn(p, dest, src, flags)
|
||||
elif needsComplexAssignment(ty):
|
||||
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
|
||||
discard getTypeDesc(p.module, ty)
|
||||
internalAssert ty.n != nil
|
||||
|
|
@ -409,7 +421,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
|||
d.k = locData
|
||||
d.t = getUniqueType(t)
|
||||
d.r = r
|
||||
d.a = -1
|
||||
|
||||
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||
var a: TLoc
|
||||
|
|
@ -425,7 +436,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
|||
d.k = locExpr
|
||||
d.t = getUniqueType(t)
|
||||
d.r = r
|
||||
d.a = -1
|
||||
|
||||
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
var a, b: TLoc
|
||||
|
|
@ -647,13 +657,16 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
||||
getSimpleTypeDesc(p.module, e.typ)]))
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}:
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||
let mt = mapType(e.sons[0].typ)
|
||||
if mt in {ctArray, ctPtrToArray} and not enforceDeref:
|
||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||
#if e[0].kind != nkBracketExpr:
|
||||
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
|
||||
expr(p, e.sons[0], d)
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
case skipTypes(a.t, abstractInst).kind
|
||||
of tyRef:
|
||||
|
|
@ -663,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
|||
of tyPtr:
|
||||
d.s = OnUnknown # BUGFIX!
|
||||
else: internalError(e.info, "genDeref " & $a.t.kind)
|
||||
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
|
||||
if enforceDeref and mt == ctPtrToArray:
|
||||
# we lie about the type for better C interop: 'ptr array[3,T]' is
|
||||
# translated to 'ptr T', but for deref'ing this produces wrong code.
|
||||
# See tmissingderef. So we get rid of the deref instead. The codegen
|
||||
# ends up using 'memcpy' for the array assignment,
|
||||
# so the '&' and '*' cancel out:
|
||||
putIntoDest(p, d, a.t.sons[0], rdLoc(a))
|
||||
else:
|
||||
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
|
||||
|
||||
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||
# careful 'addr(myptrToArray)' needs to get the ampersand:
|
||||
|
|
@ -723,7 +744,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
|||
internalError(e.info, "genRecordField")
|
||||
field = lookupInRecord(ty.n, f.name)
|
||||
if field != nil: break
|
||||
if gCmd != cmdCompileToCpp: app(r, ".Sup")
|
||||
if not p.module.compileToCpp: app(r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil: internalError(e.info, "genRecordField 2 ")
|
||||
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
|
||||
|
|
@ -775,7 +796,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
|||
assert(ty.kind in {tyTuple, tyObject})
|
||||
field = lookupInRecord(ty.n, f.name)
|
||||
if field != nil: break
|
||||
if gCmd != cmdCompileToCpp: app(r, ".Sup")
|
||||
if not p.module.compileToCpp: app(r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil: internalError(e.info, "genCheckedRecordField")
|
||||
if field.loc.r == nil:
|
||||
|
|
@ -786,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
|||
else:
|
||||
genRecordField(p, e.sons[0], d)
|
||||
|
||||
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[1], b)
|
||||
initLocExpr(p, x, a)
|
||||
initLocExpr(p, y, b)
|
||||
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
||||
var first = intLiteral(firstOrd(ty))
|
||||
# emit range check:
|
||||
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
|
||||
if not isConstExpr(e.sons[1]):
|
||||
if not isConstExpr(y):
|
||||
# semantic pass has already checked for const index expressions
|
||||
if firstOrd(ty) == 0:
|
||||
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
|
||||
|
|
@ -804,26 +825,26 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
|
||||
rdCharLoc(b), first, intLiteral(lastOrd(ty)))
|
||||
else:
|
||||
let idx = getOrdValue(e.sons[1])
|
||||
let idx = getOrdValue(y)
|
||||
if idx < firstOrd(ty) or idx > lastOrd(ty):
|
||||
localError(e.info, errIndexOutOfBounds)
|
||||
localError(x.info, errIndexOutOfBounds)
|
||||
d.inheritLocation(a)
|
||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
|
||||
|
||||
proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[1], b)
|
||||
initLocExpr(p, x, a)
|
||||
initLocExpr(p, y, b)
|
||||
var ty = skipTypes(a.t, abstractVarRange)
|
||||
if d.k == locNone: d.s = a.s
|
||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
|
||||
proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[1], b) # emit range check:
|
||||
initLocExpr(p, x, a)
|
||||
initLocExpr(p, y, b) # emit range check:
|
||||
if optBoundsCheck in p.options:
|
||||
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
|
||||
|
|
@ -831,10 +852,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
|
||||
proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
||||
proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
initLocExpr(p, e.sons[1], b)
|
||||
initLocExpr(p, x, a)
|
||||
initLocExpr(p, y, b)
|
||||
var ty = skipTypes(a.t, abstractVarRange)
|
||||
if ty.kind in {tyRef, tyPtr}:
|
||||
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
||||
|
|
@ -842,11 +863,11 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
if ty.kind == tyString:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField())
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField())
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
if d.k == locNone: d.s = OnHeap
|
||||
d.heapRoot = a.r
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
|
|
@ -854,6 +875,17 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
|||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
|
||||
|
||||
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
||||
case ty.kind
|
||||
of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d)
|
||||
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
|
||||
of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
|
||||
of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
|
||||
of tyTuple: genTupleElem(p, n, d)
|
||||
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
|
||||
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# how to generate code?
|
||||
# 'expr1 and expr2' becomes:
|
||||
|
|
@ -895,20 +927,21 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
|||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# is threadsafe.
|
||||
internalAssert n.kind == nkBracket
|
||||
discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
|
||||
var args: PRope = nil
|
||||
var a: TLoc
|
||||
for i in countup(1, n.len-1):
|
||||
for i in countup(0, n.len-1):
|
||||
initLocExpr(p, n.sons[i], a)
|
||||
appf(args, ", ($1)->data", [rdLoc(a)])
|
||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||
makeCString(repeatStr(n.len-1, "%s") & tnl), args)
|
||||
makeCString(repeatStr(n.len, "%s") & tnl), args)
|
||||
|
||||
proc gcUsage(n: PNode) =
|
||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||
|
||||
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||
# <Nimrod code>
|
||||
# <Nim code>
|
||||
# s = 'Hello ' & name & ', how do you feel?' & 'z'
|
||||
#
|
||||
# <generated C code>
|
||||
|
|
@ -939,7 +972,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
|||
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
||||
inc(L, len(e.sons[i + 1].strVal))
|
||||
else:
|
||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
|
||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
||||
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
||||
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
|
||||
app(p.s(cpsStmts), appends)
|
||||
|
|
@ -951,7 +984,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
|||
gcUsage(e)
|
||||
|
||||
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
# <Nimrod code>
|
||||
# <Nim code>
|
||||
# s &= 'Hello ' & name & ', how do you feel?' & 'z'
|
||||
# // BUG: what if s is on the left side too?
|
||||
# <generated C code>
|
||||
|
|
@ -979,7 +1012,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
|||
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
||||
inc(L, len(e.sons[i + 2].strVal))
|
||||
else:
|
||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
|
||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
||||
app(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
||||
rdLoc(dest), rdLoc(a)))
|
||||
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
||||
|
|
@ -992,7 +1025,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
|||
# seq &= x -->
|
||||
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
||||
# seq->data[seq->len-1] = x;
|
||||
let seqAppendPattern = if gCmd != cmdCompileToCpp:
|
||||
let seqAppendPattern = if not p.module.compileToCpp:
|
||||
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
||||
else:
|
||||
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
||||
|
|
@ -1005,7 +1038,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
|||
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
|
||||
keepAlive(p, a)
|
||||
initLoc(dest, locExpr, b.t, OnHeap)
|
||||
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField())
|
||||
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p))
|
||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||
gcUsage(e)
|
||||
|
||||
|
|
@ -1099,11 +1132,11 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
|||
while ty != nil:
|
||||
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
||||
if field != nil: break
|
||||
if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
|
||||
if not p.module.compileToCpp: app(tmp2.r, ".Sup")
|
||||
ty = getUniqueType(ty.sons[0])
|
||||
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
|
||||
if it.len == 3 and optFieldCheck in p.options:
|
||||
genFieldCheck(p, it.sons[2], r, field)
|
||||
genFieldCheck(p, it.sons[2], tmp2.r, field)
|
||||
app(tmp2.r, ".")
|
||||
app(tmp2.r, field.loc.r)
|
||||
tmp2.k = locTemp
|
||||
|
|
@ -1200,8 +1233,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
|||
if t.kind != tyVar: nilCheck = r
|
||||
r = rfmt(nil, "(*$1)", r)
|
||||
t = skipTypes(t.lastSon, typedescInst)
|
||||
if gCmd != cmdCompileToCpp:
|
||||
while (t.kind == tyObject) and (t.sons[0] != nil):
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
app(r, ~".Sup")
|
||||
t = skipTypes(t.sons[0], typedescInst)
|
||||
if isObjLackingTypeField(t):
|
||||
|
|
@ -1246,7 +1279,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
|||
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
||||
of tyString, tySequence:
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField()]))
|
||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
||||
of tyArray, tyArrayConstr:
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
||||
|
|
@ -1289,7 +1322,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
||||
else: unaryExpr(p, e, d, "strlen($1)")
|
||||
of tyString, tySequence:
|
||||
if gCmd != cmdCompileToCpp:
|
||||
if not p.module.compileToCpp:
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
|
||||
else: unaryExpr(p, e, d, "$1->Sup.len")
|
||||
else:
|
||||
|
|
@ -1307,7 +1340,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
|||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
var t = skipTypes(e.sons[1].typ, abstractVar)
|
||||
let setLenPattern = if gCmd != cmdCompileToCpp:
|
||||
let setLenPattern = if not p.module.compileToCpp:
|
||||
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
|
||||
else:
|
||||
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
|
||||
|
|
@ -1508,7 +1541,6 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
|||
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
|
||||
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
|
||||
tmp.k = locExpr
|
||||
tmp.a = -1
|
||||
tmp.t = srct
|
||||
tmp.s = OnStack
|
||||
tmp.flags = {}
|
||||
|
|
@ -1564,11 +1596,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
|||
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
|
||||
initLocExpr(p, e.sons[2], x)
|
||||
putIntoDest(p, d, e.typ,
|
||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
|
||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
|
||||
initLocExpr(p, e.sons[1], x)
|
||||
putIntoDest(p, d, e.typ,
|
||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
|
||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
else:
|
||||
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
||||
|
||||
|
|
@ -1673,7 +1705,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
||||
genCall(p, e, d)
|
||||
of mReset: genReset(p, e)
|
||||
of mEcho: genEcho(p, e)
|
||||
of mEcho: genEcho(p, e[1].skipConv)
|
||||
of mArrToSeq: genArrToSeq(p, e, d)
|
||||
of mNLen..mNError:
|
||||
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
||||
|
|
@ -1695,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
|
||||
proc genConstExpr(p: BProc, n: PNode): PRope
|
||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||
if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
|
||||
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
|
||||
var t = getUniqueType(n.typ)
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
|
|
@ -1827,7 +1859,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
if t.kind != tyVar: nilCheck = r
|
||||
r = ropef("(*$1)", [r])
|
||||
t = skipTypes(t.lastSon, abstractInst)
|
||||
if gCmd != cmdCompileToCpp:
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
app(r, ".Sup")
|
||||
t = skipTypes(t.sons[0], abstractInst)
|
||||
|
|
@ -1845,22 +1877,38 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
[getTypeDesc(p.module, dest), addrLoc(a)]))
|
||||
|
||||
proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
if gCmd == cmdCompileToCpp:
|
||||
if p.module.compileToCpp:
|
||||
expr(p, n.sons[0], d) # downcast does C++ for us
|
||||
else:
|
||||
var dest = skipTypes(n.typ, abstractPtrs)
|
||||
var src = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||
|
||||
var arg = n.sons[0]
|
||||
while arg.kind == nkObjDownConv: arg = arg.sons[0]
|
||||
|
||||
var src = skipTypes(arg.typ, abstractPtrs)
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
initLocExpr(p, arg, a)
|
||||
var r = rdLoc(a)
|
||||
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and
|
||||
n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}:
|
||||
let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
|
||||
if isRef:
|
||||
app(r, "->Sup")
|
||||
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
||||
r = con("&", r)
|
||||
else:
|
||||
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
||||
putIntoDest(p, d, n.typ, r)
|
||||
app(r, ".Sup")
|
||||
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
||||
if isRef:
|
||||
# it can happen that we end up generating '&&x->Sup' here, so we pack
|
||||
# the '&x->Sup' into a temporary and then those address is taken
|
||||
# (see bug #837). However sometimes using a temporary is not correct:
|
||||
# init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
|
||||
# this by ensuring the destination is also a pointer:
|
||||
if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||
getTemp(p, n.typ, d)
|
||||
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
|
||||
else:
|
||||
r = con("&", r)
|
||||
putIntoDest(p, d, n.typ, r)
|
||||
else:
|
||||
putIntoDest(p, d, n.typ, r)
|
||||
|
||||
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
var t = getUniqueType(n.typ)
|
||||
|
|
@ -1978,16 +2026,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
of nkCast: genCast(p, n, d)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
|
||||
of nkHiddenAddr, nkAddr: genAddr(p, n, d)
|
||||
of nkBracketExpr:
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
||||
case ty.kind
|
||||
of tyArray, tyArrayConstr: genArrayElem(p, n, d)
|
||||
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d)
|
||||
of tySequence, tyString: genSeqElem(p, n, d)
|
||||
of tyCString: genCStringElem(p, n, d)
|
||||
of tyTuple: genTupleElem(p, n, d)
|
||||
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
of nkBracketExpr: genBracketExpr(p, n, d)
|
||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
|
||||
of nkDotExpr: genRecordField(p, n, d)
|
||||
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
|
||||
|
|
@ -2031,7 +2070,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
initLocExpr(p, n.sons[0], a)
|
||||
of nkAsmStmt: genAsmStmt(p, n)
|
||||
of nkTryStmt:
|
||||
if gCmd == cmdCompileToCpp: genTryCpp(p, n, d)
|
||||
if p.module.compileToCpp: genTryCpp(p, n, d)
|
||||
else: genTry(p, n, d)
|
||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||
of nkTypeSection:
|
||||
|
|
@ -2043,6 +2082,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
discard
|
||||
of nkPragma: genPragma(p, n)
|
||||
of nkPragmaBlock: expr(p, n.lastSon, d)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
if (n.sons[genericParamsPos].kind == nkEmpty):
|
||||
var prc = n.sons[namePos].sym
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -83,7 +83,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
|
|||
inc i
|
||||
s.add('}')
|
||||
|
||||
proc writeIntSet(a: TIntSet, s: var string) =
|
||||
proc writeIntSet(a: IntSet, s: var string) =
|
||||
var i = 0
|
||||
for x in items(a):
|
||||
if i == 10:
|
||||
|
|
@ -200,7 +200,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
|
|||
idTablePut(result, newFakeType(key), value.toRope)
|
||||
inc L.bufpos
|
||||
|
||||
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
|
||||
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
|
||||
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
|
||||
inc L.bufpos
|
||||
while ^L.bufpos != '}':
|
||||
|
|
@ -249,7 +249,7 @@ proc readMergeInfo*(cfilename: string, m: BModule) =
|
|||
break
|
||||
|
||||
type
|
||||
TMergeSections = object {.pure.}
|
||||
TMergeSections = object
|
||||
f: TCFileSections
|
||||
p: TCProcSections
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) =
|
|||
if useLowering:
|
||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||
return
|
||||
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n.sons[L-1], tup)
|
||||
var t = tup.t
|
||||
|
|
@ -69,10 +68,21 @@ proc genVarTuple(p: BProc, n: PNode) =
|
|||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
|
||||
|
||||
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
|
||||
ri.sons[0].sym.magic == mNone):
|
||||
genAsgnCall(p, le, ri, a)
|
||||
elif ri.kind in {nkDerefExpr, nkHiddenDeref}:
|
||||
# this is a hacky way to fix #1181 (tmissingderef)::
|
||||
#
|
||||
# var arr1 = cast[ptr array[4, int8]](addr foo)[]
|
||||
#
|
||||
# However, fixing this properly really requires modelling 'array' as
|
||||
# a 'struct' in C to preserve dereferencing semantics completely. Not
|
||||
# worth the effort until version 1.0 is out.
|
||||
genDeref(p, ri, a, enforceDeref=true)
|
||||
else:
|
||||
expr(p, ri, a)
|
||||
|
||||
|
|
@ -294,8 +304,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
|||
|
||||
var alreadyPoppedCnt = p.inExceptBlock
|
||||
for i in countup(1, howManyTrys):
|
||||
|
||||
if gCmd != cmdCompileToCpp:
|
||||
if not p.module.compileToCpp:
|
||||
# Pop safe points generated by try
|
||||
if alreadyPoppedCnt > 0:
|
||||
dec alreadyPoppedCnt
|
||||
|
|
@ -317,7 +326,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
|||
for i in countdown(howManyTrys-1, 0):
|
||||
p.nestedTryStmts.add(stack[i])
|
||||
|
||||
if gCmd != cmdCompileToCpp:
|
||||
if not p.module.compileToCpp:
|
||||
# Pop exceptions that was handled by the
|
||||
# except-blocks we are in
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
|
|
@ -448,7 +457,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
|||
assert(t.sons[0].kind == nkSym)
|
||||
var sym = t.sons[0].sym
|
||||
sym.loc.k = locOther
|
||||
sym.loc.a = p.breakIdx
|
||||
sym.position = p.breakIdx+1
|
||||
expr(p, t.sons[1], d)
|
||||
endBlock(p)
|
||||
|
||||
|
|
@ -487,7 +496,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
|||
assert(t.sons[0].kind == nkSym)
|
||||
var sym = t.sons[0].sym
|
||||
assert(sym.loc.k == locOther)
|
||||
idx = sym.loc.a
|
||||
idx = sym.position-1
|
||||
else:
|
||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
|
||||
|
|
@ -501,8 +510,10 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
|||
lineF(p, cpsStmts, "goto $1;$n", [label])
|
||||
|
||||
proc getRaiseFrmt(p: BProc): string =
|
||||
if gCmd == cmdCompileToCpp:
|
||||
if p.module.compileToCpp:
|
||||
result = "throw NimException($1, $2);$n"
|
||||
elif getCompilerProc("Exception") != nil:
|
||||
result = "#raiseException((#Exception*)$1, $2);$n"
|
||||
else:
|
||||
result = "#raiseException((#E_Base*)$1, $2);$n"
|
||||
|
||||
|
|
@ -520,10 +531,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
|||
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
|
||||
genLineDir(p, t)
|
||||
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
|
||||
else:
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
# reraise the last exception:
|
||||
if gCmd == cmdCompileToCpp:
|
||||
if p.module.compileToCpp:
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n")
|
||||
|
|
@ -559,7 +570,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
|||
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr,
|
||||
until: int, a: TLoc): TLabel =
|
||||
# generate a C-if statement for a Nimrod case statement
|
||||
# generate a C-if statement for a Nim case statement
|
||||
var labId = p.labels
|
||||
for i in 1..until:
|
||||
inc(p.labels)
|
||||
|
|
@ -747,7 +758,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
|||
i, length, blen: int
|
||||
genLineDir(p, t)
|
||||
exc = getTempName()
|
||||
discard cgsym(p.module, "E_Base")
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
discard cgsym(p.module, "E_Base")
|
||||
add(p.nestedTryStmts, t)
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t.sons[0], d)
|
||||
|
|
@ -784,7 +798,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
|||
startBlock(p)
|
||||
var finallyBlock = t.lastSon
|
||||
if finallyBlock.kind == nkFinally:
|
||||
expr(p, finallyBlock.sons[0], d)
|
||||
#expr(p, finallyBlock.sons[0], d)
|
||||
genStmts(p, finallyBlock.sons[0])
|
||||
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
endBlock(p)
|
||||
|
||||
|
|
@ -793,7 +809,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
|||
|
||||
discard pop(p.nestedTryStmts)
|
||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||
exprBlock(p, t.sons[i].sons[0], d)
|
||||
genSimpleBlock(p, t.sons[i].sons[0])
|
||||
|
||||
proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
# code to generate:
|
||||
|
|
@ -829,7 +845,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName()
|
||||
discard cgsym(p.module, "E_Base")
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
discard cgsym(p.module, "E_Base")
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||
if isDefined("nimStdSetjmp"):
|
||||
|
|
@ -882,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
|||
endBlock(p) # end of else block
|
||||
if i < length and t.sons[i].kind == nkFinally:
|
||||
p.finallySafePoints.add(safePoint)
|
||||
exprBlock(p, t.sons[i].sons[0], d)
|
||||
genSimpleBlock(p, t.sons[i].sons[0])
|
||||
discard pop(p.finallySafePoints)
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -57,6 +57,9 @@ proc generateThreadLocalStorage(m: BModule) =
|
|||
|
||||
proc generateThreadVarsSize(m: BModule) =
|
||||
if nimtv != nil:
|
||||
app(m.s[cfsProcs],
|
||||
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)
|
||||
|
||||
let externc = if gCmd != cmdCompileToCpp and
|
||||
sfCompileToCpp in m.module.flags: "extern \"C\""
|
||||
else: ""
|
||||
appf(m.s[cfsProcs],
|
||||
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
|
||||
[externc.toRope])
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -49,8 +49,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
|||
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
|
||||
else: internalError(n.info, "genTraverseProc()")
|
||||
|
||||
proc parentObj(accessor: PRope): PRope {.inline.} =
|
||||
if gCmd != cmdCompileToCpp:
|
||||
proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
|
||||
if not m.compileToCpp:
|
||||
result = ropef("$1.Sup", accessor)
|
||||
else:
|
||||
result = accessor
|
||||
|
|
@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
|||
lineF(p, cpsStmts, "}$n")
|
||||
of tyObject:
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
genTraverseProc(c, accessor.parentObj, typ.sons[i])
|
||||
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
|
||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||
of tyTuple:
|
||||
let typ = getUniqueType(typ)
|
||||
|
|
@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
|||
var i: TLoc
|
||||
getTemp(p, getSysType(tyInt), i)
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
|
||||
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
|
||||
i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
|
||||
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
|
||||
lineF(p, cpsStmts, "}$n")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -162,10 +162,14 @@ proc mapReturnType(typ: PType): TCTypeKind =
|
|||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||
else: result = mapType(typ)
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
||||
proc needsComplexAssignment(typ: PType): bool =
|
||||
result = containsGarbageCollectedRef(typ)
|
||||
|
||||
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||
(typ.sons[0] == nil) or isPureObject(typ))
|
||||
|
||||
proc isInvalidReturnType(rettype: PType): bool =
|
||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||
# such a poor programming language.
|
||||
|
|
@ -177,10 +181,12 @@ proc isInvalidReturnType(rettype: PType): bool =
|
|||
of ctArray:
|
||||
result = not (skipTypes(rettype, typedescInst).kind in
|
||||
{tyVar, tyRef, tyPtr})
|
||||
of ctStruct:
|
||||
result = needsComplexAssignment(skipTypes(rettype, typedescInst))
|
||||
of ctStruct:
|
||||
let t = skipTypes(rettype, typedescInst)
|
||||
result = needsComplexAssignment(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||
else: result = false
|
||||
|
||||
|
||||
const
|
||||
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
|
||||
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
||||
|
|
@ -228,7 +234,7 @@ proc fillResult(param: PSym) =
|
|||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
|
||||
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
|
||||
proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope =
|
||||
when false:
|
||||
if t.Kind in {tyRef, tyPtr, tyVar}:
|
||||
var b = skipTypes(t.lastson, typedescInst)
|
||||
|
|
@ -243,7 +249,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
|
|||
result = OnUnknown
|
||||
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
check: var TIntSet, declareEnvironment=true) =
|
||||
check: var IntSet, declareEnvironment=true) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
rettype = ~"void"
|
||||
|
|
@ -330,7 +336,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
|||
of tyNil: result = typeNameOrLiteral(typ, "0")
|
||||
of tyInt..tyUInt64:
|
||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
||||
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||
of tyDistinct, tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||
else: result = nil
|
||||
|
||||
proc getTypePre(m: BModule, typ: PType): PRope =
|
||||
|
|
@ -342,8 +348,8 @@ proc getTypePre(m: BModule, typ: PType): PRope =
|
|||
proc structOrUnion(t: PType): PRope =
|
||||
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||
|
||||
proc getForwardStructFormat(): string =
|
||||
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
|
||||
proc getForwardStructFormat(m: BModule): string =
|
||||
if m.compileToCpp: result = "$1 $2;$n"
|
||||
else: result = "typedef $1 $2 $2;$n"
|
||||
|
||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
|
|
@ -355,7 +361,7 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
|||
of tySequence, tyTuple, tyObject:
|
||||
result = getTypeName(typ)
|
||||
if not isImportedType(typ):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(typ), result])
|
||||
idTablePut(m.forwTypeCache, typ, result)
|
||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||
|
|
@ -370,7 +376,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
|||
|
||||
proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
accessExpr: PRope, rectype: PType,
|
||||
check: var TIntSet): PRope =
|
||||
check: var IntSet): PRope =
|
||||
var
|
||||
ae, uname, sname, a: PRope
|
||||
k: PNode
|
||||
|
|
@ -419,19 +425,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
|||
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
|
||||
else: internalError(n.info, "genRecordFieldsAux()")
|
||||
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
|
||||
|
||||
proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var TIntSet): PRope =
|
||||
check: var IntSet): PRope =
|
||||
# declare the record:
|
||||
var hasField = false
|
||||
|
||||
var attribute: PRope =
|
||||
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
|
||||
if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
|
||||
else: nil
|
||||
|
||||
result = ropecg(m, CC[ccompiler].structStmtFmt,
|
||||
result = ropecg(m, CC[cCompiler].structStmtFmt,
|
||||
[structOrUnion(typ), name, attribute])
|
||||
|
||||
if typ.kind == tyObject:
|
||||
|
|
@ -442,7 +448,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
|||
else:
|
||||
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
|
||||
hasField = true
|
||||
elif gCmd == cmdCompileToCpp:
|
||||
elif m.compileToCpp:
|
||||
appcg(m, result, " : public $1 {$n",
|
||||
[getTypeDescAux(m, typ.sons[0], check)])
|
||||
hasField = true
|
||||
|
|
@ -461,7 +467,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
|||
app(result, "};" & tnl)
|
||||
|
||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||
check: var TIntSet): PRope =
|
||||
check: var IntSet): PRope =
|
||||
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||
var desc: PRope = nil
|
||||
for i in countup(0, sonsLen(typ) - 1):
|
||||
|
|
@ -474,7 +480,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
|||
proc pushType(m: BModule, typ: PType) =
|
||||
add(m.typeStack, typ)
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
# returns only the type's name
|
||||
var
|
||||
name, rettype, desc, recdesc: PRope
|
||||
|
|
@ -538,7 +544,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
|||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
assert(cacheGetType(m.typeCache, t) == nil)
|
||||
|
|
@ -550,7 +556,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
|||
cSeq = "struct $2 {$n" &
|
||||
" #TGenericSeq Sup;$n"
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
(if gCmd == cmdCompileToCpp: cppSeq else: cSeq) &
|
||||
(if m.compileToCpp: cppSeq else: cSeq) &
|
||||
" $1 data[SEQ_DECL_SIZE];$n" &
|
||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||
else:
|
||||
|
|
@ -570,7 +576,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
|||
if result == nil:
|
||||
result = getTypeName(t)
|
||||
if not isImportedType(t):
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||
[structOrUnion(t), result])
|
||||
idTablePut(m.forwTypeCache, t, result)
|
||||
idTablePut(m.typeCache, t, result) # always call for sideeffects:
|
||||
|
|
@ -678,10 +684,6 @@ when false:
|
|||
var tmp = getNimType(m)
|
||||
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
|
||||
|
||||
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||
(typ.sons[0] == nil) or isPureObject(typ))
|
||||
|
||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
var nimtypeKind: int
|
||||
#allocMemTI(m, typ, name)
|
||||
|
|
@ -898,7 +900,7 @@ include ccgtrav
|
|||
|
||||
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||
genProc(m, s)
|
||||
appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n",
|
||||
appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
||||
[result, s.loc.r])
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -149,7 +149,7 @@ proc getUniqueType*(key: PType): PType =
|
|||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
||||
proc tableGetType*(tab: TIdTable, key: PType): PObject =
|
||||
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
|
||||
# returns nil if we need to declare this type
|
||||
result = idTableGet(tab, key)
|
||||
if (result == nil) and (tab.counter > 0):
|
||||
|
|
@ -171,7 +171,7 @@ proc mangle*(name: string): string =
|
|||
## Lowercases the given name and manges any non-alphanumeric characters
|
||||
## so they are represented as `HEX____`. If the name starts with a number,
|
||||
## `N` is prepended
|
||||
result = ""
|
||||
result = newStringOfCap(name.len)
|
||||
case name[0]
|
||||
of Letters:
|
||||
result.add(name[0].toLower)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -55,7 +55,6 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
|||
result.s = s
|
||||
result.t = getUniqueType(typ)
|
||||
result.r = nil
|
||||
result.a = - 1
|
||||
result.flags = {}
|
||||
|
||||
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
||||
|
|
@ -63,7 +62,6 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
|||
if a.k == locNone:
|
||||
a.k = k
|
||||
a.t = getUniqueType(typ)
|
||||
a.a = - 1
|
||||
a.s = s
|
||||
if a.r == nil: a.r = r
|
||||
|
||||
|
|
@ -139,7 +137,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
|||
if i - 1 >= start:
|
||||
app(result, substr(frmt, start, i - 1))
|
||||
|
||||
const compileTimeRopeFmt = not defined(booting)
|
||||
const compileTimeRopeFmt = false
|
||||
|
||||
when compileTimeRopeFmt:
|
||||
import macros
|
||||
|
|
@ -186,7 +184,7 @@ when compileTimeRopeFmt:
|
|||
while s[i] in IdentChars: inc i
|
||||
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
|
||||
start = i
|
||||
else: nil
|
||||
else: discard
|
||||
|
||||
while i < length:
|
||||
if s[i] != '$' and s[i] != '#': inc i
|
||||
|
|
@ -201,7 +199,7 @@ when compileTimeRopeFmt:
|
|||
## the compilation of nimrod itself or will the macro execution time
|
||||
## offset the gains?
|
||||
result = newCall(bindSym"ropeConcat")
|
||||
for frag in fmtStringFragments(fmt.strVal):
|
||||
for frag in fmtStringFragments(fmt):
|
||||
case frag.kind
|
||||
of ffSym:
|
||||
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
|
||||
|
|
@ -286,7 +284,7 @@ proc genLineDir(p: BProc, t: PNode) =
|
|||
line.toRope, makeCString(toFilename(t.info)))
|
||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||
{optLineTrace, optStackTrace}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
|
||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||
line.toRope, t.info.quotedFilename)
|
||||
|
||||
|
|
@ -297,6 +295,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym)
|
|||
proc emulatedThreadVars(): bool {.inline.}
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
|
||||
template compileToCpp(m: BModule): expr =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||
|
||||
include "ccgtypes.nim"
|
||||
|
||||
# ------------------------------ Manager of temporaries ------------------
|
||||
|
|
@ -309,7 +310,7 @@ proc rdLoc(a: TLoc): PRope =
|
|||
proc addrLoc(a: TLoc): PRope =
|
||||
result = a.r
|
||||
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
|
||||
result = con("&", result)
|
||||
result = con("(&", result).con(")")
|
||||
|
||||
proc rdCharLoc(a: TLoc): PRope =
|
||||
# read a location that may need a char-cast:
|
||||
|
|
@ -326,7 +327,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
|||
var r = rdLoc(a)
|
||||
if not takeAddr: r = ropef("(*$1)", [r])
|
||||
var s = skipTypes(t, abstractInst)
|
||||
if gCmd != cmdCompileToCpp:
|
||||
if not p.module.compileToCpp:
|
||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||
app(r, ".Sup")
|
||||
s = skipTypes(s.sons[0], abstractInst)
|
||||
|
|
@ -407,7 +408,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
|||
result.r = con("LOC", toRope(p.labels))
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||
result.k = locTemp
|
||||
result.a = - 1
|
||||
#result.a = - 1
|
||||
result.t = getUniqueType(t)
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
|
|
@ -425,7 +426,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
|||
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
||||
inc(p.gcFrameId)
|
||||
result.k = locTemp
|
||||
result.a = -1
|
||||
#result.a = -1
|
||||
result.t = toKeepAlive.t
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
|
|
@ -505,9 +506,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
|||
if sfRegister in s.flags: app(decl, " register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# app(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags or (p.nestedTryStmts.len > 0 and
|
||||
gCmd != cmdCompileToCpp):
|
||||
app(decl, " volatile")
|
||||
if sfVolatile in s.flags: app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
else:
|
||||
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
||||
|
|
@ -587,8 +586,8 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
|||
initLoc(result, locNone, e.typ, OnUnknown)
|
||||
expr(p, e, result)
|
||||
|
||||
proc lenField: PRope {.inline.} =
|
||||
result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")
|
||||
proc lenField(p: BProc): PRope =
|
||||
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
|
||||
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
|
||||
|
||||
|
|
@ -812,7 +811,12 @@ proc genProcAux(m: BModule, prc: PSym) =
|
|||
app(generatedProc, returnStmt)
|
||||
app(generatedProc, ~"}$N")
|
||||
app(m.s[cfsProcs], generatedProc)
|
||||
|
||||
|
||||
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = sfCompileToCpp in m.module.flags and
|
||||
sfCompileToCpp notin sym.getModule().flags and
|
||||
gCmd != cmdCompileToCpp
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if lfNoDecl in sym.loc.flags: return
|
||||
|
|
@ -824,6 +828,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
|||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
|
||||
header = con("extern \"C\" ", header)
|
||||
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
||||
header.app(" __attribute__((naked))")
|
||||
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
|
|
@ -915,30 +921,30 @@ proc addIntTypes(result: var PRope) {.inline.} =
|
|||
appf(result, "#define NIM_INTBITS $1", [
|
||||
platform.CPU[targetCPU].intSize.toRope])
|
||||
|
||||
proc getCopyright(cfilenoext: string): PRope =
|
||||
proc getCopyright(cfile: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N",
|
||||
"; Generated by Nimrod Compiler v$1$N" &
|
||||
"; Generated by Nim Compiler v$1$N" &
|
||||
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
||||
else:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
||||
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N" &
|
||||
"/* Compiled for: $2, $3, $4 */$N" &
|
||||
"/* Command for C compiler:$n $5 */$N",
|
||||
"; Generated by Nimrod Compiler v$1$N" &
|
||||
"; Generated by Nim Compiler v$1$N" &
|
||||
"; (c) 2014 Andreas Rumpf$N" &
|
||||
"; Compiled for: $2, $3, $4$N" &
|
||||
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||
toRope(getCompileCFileCmd(cfilenoext))])
|
||||
toRope(getCompileCFileCmd(cfile))])
|
||||
|
||||
proc getFileHeader(cfilenoext: string): PRope =
|
||||
result = getCopyright(cfilenoext)
|
||||
proc getFileHeader(cfile: string): PRope =
|
||||
result = getCopyright(cfile)
|
||||
addIntTypes(result)
|
||||
|
||||
proc genFilenames(m: BModule): PRope =
|
||||
|
|
@ -963,7 +969,7 @@ proc genMainProc(m: BModule) =
|
|||
"\tvoid (*volatile inner)();$N" &
|
||||
"\tsystemDatInit();$N" &
|
||||
"\tinner = PreMainInner;$N" &
|
||||
"$4" &
|
||||
"$4$5" &
|
||||
"\t(*inner)();$N" &
|
||||
"}$N$N"
|
||||
|
||||
|
|
@ -1051,12 +1057,16 @@ proc genMainProc(m: BModule) =
|
|||
gBreakpoints.app(m.genFilenames)
|
||||
|
||||
let initStackBottomCall =
|
||||
if emulatedThreadVars() or
|
||||
platform.targetOS == osStandalone: "".toRope
|
||||
if platform.targetOS == osStandalone: "".toRope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
mainDatInit, gBreakpoints, otherModsInit, initStackBottomCall])
|
||||
mainDatInit, gBreakpoints, otherModsInit,
|
||||
if emulatedThreadVars() and platform.targetOS != osStandalone:
|
||||
ropecg(m, "\t#initThreadVarsEmulation();$N")
|
||||
else:
|
||||
"".toRope,
|
||||
initStackBottomCall])
|
||||
|
||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
|
||||
if optNoMain notin gGlobalOptions:
|
||||
|
|
@ -1078,9 +1088,9 @@ proc registerModuleToMain(m: PSym) =
|
|||
var
|
||||
init = m.getInitName
|
||||
datInit = m.getDatInitName
|
||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
||||
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||
"declare void $1() noinline$N", [init])
|
||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
||||
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||
"declare void $1() noinline$N", [datInit])
|
||||
if sfSystemModule notin m.flags:
|
||||
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
||||
|
|
@ -1092,7 +1102,7 @@ proc registerModuleToMain(m: PSym) =
|
|||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname = getInitName(m.module)
|
||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
|
||||
var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [initname])
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
|
|
@ -1135,7 +1145,7 @@ proc genInitCode(m: BModule) =
|
|||
app(prc, deinitGCFrame(m.initProc))
|
||||
appf(prc, "}$N$N")
|
||||
|
||||
prc.appff("N_NOINLINE(void, $1)(void) {$N",
|
||||
prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
|
|
@ -1155,8 +1165,8 @@ proc genInitCode(m: BModule) =
|
|||
(i.ord - '0'.ord).toRope, el)
|
||||
app(m.s[cfsInitProc], ex)
|
||||
|
||||
proc genModule(m: BModule, cfilenoext: string): PRope =
|
||||
result = getFileHeader(cfilenoext)
|
||||
proc genModule(m: BModule, cfile: string): PRope =
|
||||
result = getFileHeader(cfile)
|
||||
result.app(genMergeInfo(m))
|
||||
|
||||
generateHeaders(m)
|
||||
|
|
@ -1297,7 +1307,11 @@ proc writeHeader(m: BModule) =
|
|||
writeRope(result, m.filename)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt)
|
||||
let ext =
|
||||
if m.compileToCpp: ".cpp"
|
||||
elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
|
||||
else: ".c"
|
||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
|
||||
|
||||
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||
assert optSymbolFiles in gGlobalOptions
|
||||
|
|
@ -1326,10 +1340,10 @@ proc finishModule(m: BModule) =
|
|||
dec(gForwardedProcsCounter, i)
|
||||
setLen(m.forwardedProcs, 0)
|
||||
|
||||
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
|
||||
proc shouldRecompile(code: PRope, cfile: string): bool =
|
||||
result = true
|
||||
if optForceFullMake notin gGlobalOptions:
|
||||
var objFile = toObjFile(cfilenoext)
|
||||
var objFile = toObjFile(cfile)
|
||||
if writeRopeIfNotEqual(code, cfile): return
|
||||
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
|
||||
else:
|
||||
|
|
@ -1354,26 +1368,26 @@ proc writeModule(m: BModule, pending: bool) =
|
|||
app(m.s[cfsProcHeaders], mainModProcs)
|
||||
generateThreadVarsSize(m)
|
||||
|
||||
var code = genModule(m, cfilenoext)
|
||||
var code = genModule(m, cfile)
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
tccgen.compileCCode(ropeToStr(code))
|
||||
return
|
||||
|
||||
if shouldRecompile(code, cfile, cfilenoext):
|
||||
addFileToCompile(cfilenoext)
|
||||
if shouldRecompile(code, cfile):
|
||||
addFileToCompile(cfile)
|
||||
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||
mergeFiles(cfile, m)
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
var code = genModule(m, cfilenoext)
|
||||
var code = genModule(m, cfile)
|
||||
writeRope(code, cfile)
|
||||
addFileToCompile(cfilenoext)
|
||||
addFileToCompile(cfile)
|
||||
elif not existsFile(toObjFile(cfilenoext)):
|
||||
# Consider: first compilation compiles ``system.nim`` and produces
|
||||
# ``system.c`` but then compilation fails due to an error. This means
|
||||
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
||||
addFileToCompile(cfilenoext)
|
||||
addFileToCompile(cfile)
|
||||
|
||||
addFileToLink(cfilenoext)
|
||||
|
||||
|
|
@ -1385,9 +1399,9 @@ proc updateCachedModule(m: BModule) =
|
|||
mergeFiles(cfile, m)
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
var code = genModule(m, cfilenoext)
|
||||
var code = genModule(m, cfile)
|
||||
writeRope(code, cfile)
|
||||
addFileToCompile(cfilenoext)
|
||||
addFileToCompile(cfile)
|
||||
|
||||
addFileToLink(cfilenoext)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -62,7 +62,7 @@ type
|
|||
frameLen*: int16
|
||||
|
||||
TCProc{.final.} = object # represents C proc that is currently generated
|
||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
||||
prc*: PSym # the Nim proc that this C proc belongs to
|
||||
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||
|
|
@ -101,10 +101,10 @@ type
|
|||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
forwTypeCache*: TIdTable # cache for forward declarations of types
|
||||
declaredThings*: TIntSet # things we have declared in this .c file
|
||||
declaredProtos*: TIntSet # prototypes we have declared in this .c file
|
||||
declaredThings*: IntSet # things we have declared in this .c file
|
||||
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||
headerFiles*: TLinkedList # needed headers to include
|
||||
typeInfoMarker*: TIntSet # needed for generating type information
|
||||
typeInfoMarker*: IntSet # needed for generating type information
|
||||
initProc*: BProc # code for init procedure
|
||||
postInitProc*: BProc # code to be executed after the init proc
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -155,7 +155,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
|
|||
if not sameType(t2, t):
|
||||
return true
|
||||
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
|
|
@ -164,7 +164,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
|||
if (d != high(int)):
|
||||
return d
|
||||
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
|
||||
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||
# we use shellsort here; fast and simple
|
||||
var n = len(a)
|
||||
var h = 1
|
||||
|
|
@ -183,7 +183,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
|
|||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
|
||||
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
var base = lastSon(methods[0].ast).sym
|
||||
result = base
|
||||
var paramLen = sonsLen(base.typ)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
|||
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||
wordrecg, parseutils, babelcmd, idents
|
||||
wordrecg, parseutils, nimblecmd, idents, parseopt
|
||||
|
||||
# but some have deps to imported modules. Yay.
|
||||
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
||||
|
|
@ -43,7 +43,7 @@ type
|
|||
TCmdLinePass* = enum
|
||||
passCmd1, # first pass over the command line
|
||||
passCmd2, # second pass over the command line
|
||||
passPP # preprocessor called ProcessCommand()
|
||||
passPP # preprocessor called processCommand()
|
||||
|
||||
proc processCommand*(switch: string, pass: TCmdLinePass)
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
||||
|
|
@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
|||
# implementation
|
||||
|
||||
const
|
||||
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
|
|
@ -226,6 +226,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
|||
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
|
||||
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
|
||||
of "patterns": result = contains(gOptions, optPatterns)
|
||||
of "experimental": result = gExperimentalMode
|
||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||
|
||||
proc processPath(path: string, notRelativeToProj = false): string =
|
||||
|
|
@ -234,7 +235,9 @@ proc processPath(path: string, notRelativeToProj = false): string =
|
|||
path
|
||||
else:
|
||||
options.gProjectPath / path
|
||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
|
||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
|
||||
"nim", getPrefixDir(),
|
||||
"lib", libpath,
|
||||
"home", removeTrailingDirSep(os.getHomeDir()),
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath])
|
||||
|
|
@ -280,14 +283,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "path", "p":
|
||||
expectArg(switch, arg, pass, info)
|
||||
addPath(processPath(arg), info)
|
||||
of "babelpath":
|
||||
if pass in {passCmd2, passPP} and not options.gNoBabelPath:
|
||||
of "nimblepath", "babelpath":
|
||||
# keep the old name for compat
|
||||
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg, notRelativeToProj=true)
|
||||
babelpath(path, info)
|
||||
of "nobabelpath":
|
||||
nimblePath(path, info)
|
||||
of "nonimblepath", "nobabelpath":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
options.gNoBabelPath = true
|
||||
options.gNoNimblePath = true
|
||||
of "excludepath":
|
||||
expectArg(switch, arg, pass, info)
|
||||
let path = processPath(arg)
|
||||
|
|
@ -307,8 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
expectArg(switch, arg, pass, info)
|
||||
options.docSeeSrcUrl = arg
|
||||
of "mainmodule", "m":
|
||||
expectArg(switch, arg, pass, info)
|
||||
optMainModule = arg
|
||||
discard "allow for backwards compatibility, but don't do anything"
|
||||
of "define", "d":
|
||||
expectArg(switch, arg, pass, info)
|
||||
defineSymbol(arg)
|
||||
|
|
@ -566,6 +569,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
|||
of "none": idents.firstCharIsCS = false
|
||||
else: localError(info, errGenerated,
|
||||
"'partial' or 'none' expected, but found " & arg)
|
||||
of "experimental":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
gExperimentalMode = true
|
||||
else:
|
||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||
else: invalidCmdLineOption(pass, switch, info)
|
||||
|
|
@ -574,3 +580,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) =
|
|||
var cmd, arg: string
|
||||
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
||||
processSwitch(cmd, arg, pass, gCmdLineInfo)
|
||||
|
||||
|
||||
var
|
||||
arguments* = ""
|
||||
# the arguments to be passed to the program that
|
||||
# should be run
|
||||
|
||||
proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
|
||||
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
||||
# we fix this here
|
||||
var bracketLe = strutils.find(p.key, '[')
|
||||
if bracketLe >= 0:
|
||||
var key = substr(p.key, 0, bracketLe - 1)
|
||||
var val = substr(p.key, bracketLe + 1) & ':' & p.val
|
||||
processSwitch(key, val, pass, gCmdLineInfo)
|
||||
else:
|
||||
processSwitch(p.key, p.val, pass, gCmdLineInfo)
|
||||
|
||||
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||
argsCount: var int): bool =
|
||||
if argsCount == 0:
|
||||
options.command = p.key
|
||||
else:
|
||||
if pass == passCmd1: options.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
# support UNIX style filenames anywhere for portable build scripts:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
arguments = cmdLineRest(p)
|
||||
result = true
|
||||
inc argsCount
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import
|
|||
|
||||
# We need to use a PStringTable here as defined symbols are always guaranteed
|
||||
# to be style insensitive. Otherwise hell would break lose.
|
||||
var gSymbols: PStringTable
|
||||
var gSymbols: StringTableRef
|
||||
|
||||
proc defineSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = "true"
|
||||
|
|
@ -41,12 +41,12 @@ proc countDefinedSymbols*(): int =
|
|||
for key, val in pairs(gSymbols):
|
||||
if val == "true": inc(result)
|
||||
|
||||
# For ease of bootstrapping, we keep there here and not in the global config
|
||||
# For ease of bootstrapping, we keep them here and not in the global config
|
||||
# file for now:
|
||||
const
|
||||
additionalSymbols = """
|
||||
x86 itanium x8664
|
||||
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS doslike hpux
|
||||
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS hpux
|
||||
mac
|
||||
|
||||
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
|
||||
|
|
@ -88,6 +88,7 @@ proc initDefines*() =
|
|||
defineSymbol("nimrequiresnimframe")
|
||||
defineSymbol("nimparsebiggestfloatmagic")
|
||||
defineSymbol("nimalias")
|
||||
defineSymbol("nimlocks")
|
||||
|
||||
# add platform specific symbols:
|
||||
for c in low(CPU)..high(CPU):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 =
|
|||
const
|
||||
bufSize = 8000 # don't use 8K for the memory allocator!
|
||||
var
|
||||
bin: TFile
|
||||
bin: File
|
||||
result = InitCrc32
|
||||
if not open(bin, filename):
|
||||
return # not equal if file does not exist
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -23,7 +23,7 @@ type
|
|||
id: int # for generating IDs
|
||||
toc, section: TSections
|
||||
indexValFilename: string
|
||||
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
|
||||
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
|
|
@ -41,6 +41,7 @@ proc compilerMsgHandler(filename: string, line, col: int,
|
|||
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||
globalError(newLineInfo(filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.procvar.} =
|
||||
|
|
@ -55,7 +56,7 @@ proc parseRst(text, filename: string,
|
|||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
||||
proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
new(result)
|
||||
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
||||
options.gConfigVars, filename, {roSupportRawDirective},
|
||||
|
|
@ -374,11 +375,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
|||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||
plainSymbolRope = toRope(cleanPlainSymbol)
|
||||
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
|
||||
plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
|
||||
itemIDRope = toRope(d.id)
|
||||
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
||||
symbolOrIdRope = symbolOrId.toRope
|
||||
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
|
||||
symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
|
||||
|
||||
var seeSrcRope: PRope = nil
|
||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||
|
|
@ -413,7 +414,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
|||
setIndexTerm(d[], symbolOrId, name, linkTitle,
|
||||
xmltree.escape(plainDocstring.docstringSummary))
|
||||
|
||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
|
||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||
if not isVisible(nameNode): return
|
||||
var
|
||||
name = getName(d, nameNode)
|
||||
|
|
@ -473,7 +474,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
|||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||
else: discard
|
||||
|
||||
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
|
||||
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
|
||||
case n.kind
|
||||
of nkCommentStmt:
|
||||
if n.comment != nil and startsWith(n.comment, "##"):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -26,7 +26,7 @@ proc close(p: PPassContext, n: PNode): PNode =
|
|||
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
|
||||
try:
|
||||
generateIndex(g.doc)
|
||||
except EIO:
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This file implements the FFI part of the evaluator for Nimrod code.
|
||||
## This file implements the FFI part of the evaluator for Nim code.
|
||||
|
||||
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# module for calling the different external C compilers
|
||||
# some things are read in from the configuration file
|
||||
# Module providing functions for calling the different external C compilers
|
||||
# Uses some hard-wired facts about each C/C++ compiler, plus options read
|
||||
# from a configuration file, to provide generalized procedures to compile
|
||||
# nim files.
|
||||
|
||||
import
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
||||
|
|
@ -59,6 +61,7 @@ type
|
|||
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
|
||||
proc name: TInfoCC {.compileTime.} = settings
|
||||
|
||||
# GNU C and C++ Compiler
|
||||
compiler gcc:
|
||||
result = (
|
||||
name: "gcc",
|
||||
|
|
@ -84,21 +87,24 @@ compiler gcc:
|
|||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||
hasNakedAttribute})
|
||||
|
||||
# LLVM Frontend for GCC/G++
|
||||
compiler llvmGcc:
|
||||
result = gcc()
|
||||
|
||||
result = gcc() # Uses settings from GCC
|
||||
|
||||
result.name = "llvm_gcc"
|
||||
result.compilerExe = "llvm-gcc"
|
||||
result.cppCompiler = "llvm-g++"
|
||||
result.buildLib = "llvm-ar rcs $libfile $objfiles"
|
||||
|
||||
# Clang (LLVM) C/C++ Compiler
|
||||
compiler clang:
|
||||
result = llvmGcc()
|
||||
result = llvmGcc() # Uses settings from llvmGcc
|
||||
|
||||
result.name = "clang"
|
||||
result.compilerExe = "clang"
|
||||
result.cppCompiler = "clang++"
|
||||
|
||||
# Microsoft Visual C/C++ Compiler
|
||||
compiler vcc:
|
||||
result = (
|
||||
name: "vcc",
|
||||
|
|
@ -123,6 +129,7 @@ compiler vcc:
|
|||
packedPragma: "#pragma pack(1)",
|
||||
props: {hasCpp, hasAssume, hasNakedDeclspec})
|
||||
|
||||
# Intel C/C++ Compiler
|
||||
compiler icl:
|
||||
# Intel compilers try to imitate the native ones (gcc and msvc)
|
||||
when defined(windows):
|
||||
|
|
@ -134,6 +141,7 @@ compiler icl:
|
|||
result.compilerExe = "icl"
|
||||
result.linkerExe = "icl"
|
||||
|
||||
# Local C Compiler
|
||||
compiler lcc:
|
||||
result = (
|
||||
name: "lcc",
|
||||
|
|
@ -158,6 +166,7 @@ compiler lcc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
# Borland C Compiler
|
||||
compiler bcc:
|
||||
result = (
|
||||
name: "bcc",
|
||||
|
|
@ -182,6 +191,7 @@ compiler bcc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasCpp})
|
||||
|
||||
# Digital Mars C Compiler
|
||||
compiler dmc:
|
||||
result = (
|
||||
name: "dmc",
|
||||
|
|
@ -206,6 +216,7 @@ compiler dmc:
|
|||
packedPragma: "#pragma pack(1)",
|
||||
props: {hasCpp})
|
||||
|
||||
# Watcom C Compiler
|
||||
compiler wcc:
|
||||
result = (
|
||||
name: "wcc",
|
||||
|
|
@ -230,6 +241,7 @@ compiler wcc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasCpp})
|
||||
|
||||
# Tiny C Compiler
|
||||
compiler tcc:
|
||||
result = (
|
||||
name: "tcc",
|
||||
|
|
@ -254,6 +266,7 @@ compiler tcc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {hasSwitchRange, hasComputedGoto})
|
||||
|
||||
# Pelles C Compiler
|
||||
compiler pcc:
|
||||
# Pelles C
|
||||
result = (
|
||||
|
|
@ -279,6 +292,7 @@ compiler pcc:
|
|||
packedPragma: "", # XXX: not supported yet
|
||||
props: {})
|
||||
|
||||
# Your C Compiler
|
||||
compiler ucc:
|
||||
result = (
|
||||
name: "ucc",
|
||||
|
|
@ -323,10 +337,7 @@ const
|
|||
|
||||
var
|
||||
cCompiler* = ccGcc # the used compiler
|
||||
|
||||
cExt* = ".c" # extension of generated C/C++ files
|
||||
# (can be changed to .cpp later)
|
||||
|
||||
gMixedMode*: bool # true if some module triggered C++ codegen
|
||||
cIncludes*: seq[string] = @[] # directories to search for included files
|
||||
cLibs*: seq[string] = @[] # directories to search for lib files
|
||||
cLinkedLibs*: seq[string] = @[] # libraries to link
|
||||
|
|
@ -342,7 +353,9 @@ var
|
|||
compileOptions: string = ""
|
||||
ccompilerpath: string = ""
|
||||
|
||||
proc nameToCC*(name: string): TSystemCC =
|
||||
proc nameToCC*(name: string): TSystemCC =
|
||||
## Returns the kind of compiler referred to by `name`, or ccNone
|
||||
## if the name doesn't refer to any known compiler.
|
||||
for i in countup(succ(ccNone), high(TSystemCC)):
|
||||
if cmpIgnoreStyle(name, CC[i].name) == 0:
|
||||
return i
|
||||
|
|
@ -351,17 +364,18 @@ proc nameToCC*(name: string): TSystemCC =
|
|||
proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
|
||||
# for niminst support
|
||||
let fullSuffix = (if gCmd == cmdCompileToCpp: ".cpp" & suffix else: suffix)
|
||||
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
|
||||
optCompileOnly notin gGlobalOptions:
|
||||
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
||||
platform.OS[targetOS].name & '.' &
|
||||
CC[c].name & suffix
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(fullCCname)
|
||||
if result.len == 0:
|
||||
# not overriden for this cross compilation setting?
|
||||
result = getConfigVar(CC[c].name & suffix)
|
||||
result = getConfigVar(CC[c].name & fullSuffix)
|
||||
else:
|
||||
result = getConfigVar(CC[c].name & suffix)
|
||||
result = getConfigVar(CC[c].name & fullSuffix)
|
||||
|
||||
proc setCC*(ccname: string) =
|
||||
cCompiler = nameToCC(ccname)
|
||||
|
|
@ -387,8 +401,6 @@ proc initVars*() =
|
|||
# we need to define the symbol here, because ``CC`` may have never been set!
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
if gCmd == cmdCompileToCpp: cExt = ".cpp"
|
||||
elif gCmd == cmdCompileToOC: cExt = ".m"
|
||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
if len(ccompilerpath) == 0:
|
||||
|
|
@ -397,9 +409,9 @@ proc initVars*() =
|
|||
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
||||
result = completeGeneratedFilePath(cfile, createSubDir)
|
||||
|
||||
proc toObjFile*(filenameWithoutExt: string): string =
|
||||
proc toObjFile*(filename: string): string =
|
||||
# Object file for compilation
|
||||
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
|
||||
result = changeFileExt(filename, CC[cCompiler].objExt)
|
||||
|
||||
proc addFileToCompile*(filename: string) =
|
||||
appendStr(toCompile, filename)
|
||||
|
|
@ -417,8 +429,12 @@ proc addFileToLink*(filename: string) =
|
|||
prependStr(toLink, filename)
|
||||
# BUGFIX: was ``appendStr``
|
||||
|
||||
proc execExternalProgram*(cmd: string) =
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
|
||||
proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0:
|
||||
if prettyCmd != "":
|
||||
msgWriteln(prettyCmd)
|
||||
else:
|
||||
msgWriteln(cmd)
|
||||
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
|
||||
|
||||
proc generateScript(projectFile: string, script: PRope) =
|
||||
|
|
@ -487,7 +503,7 @@ proc getLinkOptions: string =
|
|||
|
||||
proc needsExeExt(): bool {.inline.} =
|
||||
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||
(platform.hostOS == osWindows)
|
||||
(platform.hostOS == osWindows)
|
||||
|
||||
proc getCompilerExe(compiler: TSystemCC): string =
|
||||
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
|
|
@ -497,6 +513,7 @@ proc getCompilerExe(compiler: TSystemCC): string =
|
|||
|
||||
proc getLinkerExe(compiler: TSystemCC): string =
|
||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
else: compiler.getCompilerExe
|
||||
|
||||
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
|
|
@ -507,11 +524,11 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
|||
|
||||
if needsExeExt(): exe = addFileExt(exe, "exe")
|
||||
if optGenDynLib in gGlobalOptions and
|
||||
ospNeedsPIC in platform.OS[targetOS].props:
|
||||
ospNeedsPIC in platform.OS[targetOS].props:
|
||||
add(options, ' ' & CC[c].pic)
|
||||
|
||||
var includeCmd, compilePattern: string
|
||||
if not noAbsolutePaths():
|
||||
if not noAbsolutePaths():
|
||||
# compute include paths:
|
||||
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
||||
|
||||
|
|
@ -519,29 +536,31 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
|||
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
|
||||
|
||||
compilePattern = joinPath(ccompilerpath, exe)
|
||||
else:
|
||||
else:
|
||||
includeCmd = ""
|
||||
compilePattern = c.getCompilerExe
|
||||
|
||||
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
|
||||
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
|
||||
else: cfilename
|
||||
var objfile = if not isExternal or noAbsolutePaths():
|
||||
toObjFile(cfile)
|
||||
else:
|
||||
var objfile = if not isExternal or noAbsolutePaths():
|
||||
toObjFile(cfile)
|
||||
else:
|
||||
completeCFilePath(toObjFile(cfile))
|
||||
cfile = quoteShell(addFileExt(cfile, cExt))
|
||||
objfile = quoteShell(objfile)
|
||||
result = quoteShell(compilePattern % [
|
||||
"file", cfile, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
"file", cfile, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nimrod", getPrefixDir(),
|
||||
"nim", getPrefixDir(), "lib", libpath])
|
||||
add(result, ' ')
|
||||
addf(result, CC[c].compileTmpl, [
|
||||
"file", cfile, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"file", cfile, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
|
||||
proc footprint(filename: string): TCrc32 =
|
||||
# note, '><' further modifies a crc value with a string.
|
||||
result = crcFromFile(filename) ><
|
||||
platform.OS[targetOS].name ><
|
||||
platform.CPU[targetCPU].name ><
|
||||
|
|
@ -551,7 +570,7 @@ proc footprint(filename: string): TCrc32 =
|
|||
proc externalFileChanged(filename: string): bool =
|
||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||
var currentCrc = int(footprint(filename))
|
||||
var f: TFile
|
||||
var f: File
|
||||
if open(f, crcFile, fmRead):
|
||||
var line = newStringOfCap(40)
|
||||
if not f.readLine(line): line = "0"
|
||||
|
|
@ -569,14 +588,16 @@ proc addExternalFileToCompile*(filename: string) =
|
|||
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
||||
appendStr(externalToCompile, filename)
|
||||
|
||||
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
isExternal: bool) =
|
||||
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||
prettyCmds: var TStringSeq, isExternal: bool) =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
inc(fileCounter) # call the C compiler for the .c file:
|
||||
var compileCmd = getCompileCFileCmd(it.data, isExternal)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
add(cmds, compileCmd)
|
||||
let (dir, name, ext) = splitFile(it.data)
|
||||
add(prettyCmds, "CC: " & name)
|
||||
if optGenScript in gGlobalOptions:
|
||||
app(script, compileCmd)
|
||||
app(script, tnl)
|
||||
|
|
@ -592,18 +613,24 @@ proc callCCompiler*(projectfile: string) =
|
|||
var c = cCompiler
|
||||
var script: PRope = nil
|
||||
var cmds: TStringSeq = @[]
|
||||
compileCFile(toCompile, script, cmds, false)
|
||||
compileCFile(externalToCompile, script, cmds, true)
|
||||
var prettyCmds: TStringSeq = @[]
|
||||
let prettyCb = proc (idx: int) =
|
||||
echo prettyCmds[idx]
|
||||
compileCFile(toCompile, script, cmds, prettyCmds, false)
|
||||
compileCFile(externalToCompile, script, cmds, prettyCmds, true)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||
var res = 0
|
||||
if gNumberOfProcessors <= 1:
|
||||
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
|
||||
elif optListCmd in gGlobalOptions or gVerbosity > 0:
|
||||
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
||||
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
else:
|
||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||
elif gVerbosity == 1:
|
||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||
gNumberOfProcessors, prettyCb)
|
||||
else:
|
||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
if res != 0:
|
||||
if gNumberOfProcessors <= 1:
|
||||
|
|
@ -625,7 +652,6 @@ proc callCCompiler*(projectfile: string) =
|
|||
if optGenStaticLib in gGlobalOptions:
|
||||
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
||||
"objfiles", objfiles]
|
||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
||||
else:
|
||||
var linkerExe = getConfigVar(c, ".linkerexe")
|
||||
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
|
||||
|
|
@ -657,7 +683,11 @@ proc callCCompiler*(projectfile: string) =
|
|||
"objfiles", objfiles, "exefile", exefile,
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if gVerbosity == 1:
|
||||
execExternalProgram(linkCmd, "[Linking]")
|
||||
else:
|
||||
execExternalProgram(linkCmd)
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
|
|
@ -668,7 +698,7 @@ proc callCCompiler*(projectfile: string) =
|
|||
proc genMappingFiles(list: TLinkedList): PRope =
|
||||
var it = PStrEntry(list.head)
|
||||
while it != nil:
|
||||
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
|
||||
appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
proc writeMapping*(gSymbolMapping: PRope) =
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements Nimrod's standard template filter.
|
||||
# This module implements Nim's standard template filter.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
|
|
@ -148,7 +148,7 @@ proc parseLine(p: var TTmplParser) =
|
|||
inc(j)
|
||||
else:
|
||||
if p.x[j] == p.subsChar:
|
||||
# parse Nimrod expression:
|
||||
# parse Nim expression:
|
||||
inc(j)
|
||||
case p.x[j]
|
||||
of '{':
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements Nimrod's simple filters and helpers for filters.
|
||||
# This module implements Nim's simple filters and helpers for filters.
|
||||
|
||||
import
|
||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) =
|
|||
fact.sons[2] = value
|
||||
m.add fact
|
||||
|
||||
proc sameSubexprs*(m: TModel; a, b: PNode): bool =
|
||||
# This should be used to check whether two *path expressions* refer to the
|
||||
# same memory location according to 'm'. This is tricky:
|
||||
# lock a[i].guard:
|
||||
# ...
|
||||
# access a[i].guarded
|
||||
#
|
||||
# Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'.
|
||||
# However, nil checking requires exactly the same mechanism! But for now
|
||||
# we simply use sameTree and live with the unsoundness of the analysis.
|
||||
var check = newNodeI(nkCall, a.info, 3)
|
||||
check.sons[0] = newSymNode(opEq)
|
||||
check.sons[1] = a
|
||||
check.sons[2] = b
|
||||
result = m.doesImply(check) == impYes
|
||||
|
||||
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
|
||||
let branch = n.sons[i]
|
||||
if branch.kind == nkOfBranch:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -15,7 +15,7 @@ import
|
|||
hashes, strutils
|
||||
|
||||
type
|
||||
TIdObj* = object of TObject
|
||||
TIdObj* = object of RootObj
|
||||
id*: int # unique id; use this for comparisons and not the pointers
|
||||
|
||||
PIdObj* = ref TIdObj
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -53,7 +53,7 @@ proc saveMaxIds*(project: string) =
|
|||
f.close()
|
||||
|
||||
proc loadMaxIds*(project: string) =
|
||||
var f: TFile
|
||||
var f: File
|
||||
if open(f, project.toGid, fmRead):
|
||||
var line = newStringOfCap(20)
|
||||
if f.readLine(line):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -113,7 +113,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
|||
e = nextIdentIter(it, fromMod.tab)
|
||||
else: rawImportSymbol(c, s)
|
||||
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
var i: TTabIter
|
||||
var s = initTabIter(i, fromMod.tab)
|
||||
while s != nil:
|
||||
|
|
@ -126,10 +126,10 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
|||
s = nextIter(i, fromMod.tab)
|
||||
|
||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||
var exceptSet: TIntSet
|
||||
var exceptSet: IntSet
|
||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
|
||||
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||
if n.isNil: return
|
||||
case n.kind
|
||||
of nkExportStmt:
|
||||
|
|
@ -166,7 +166,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
|
|||
|
||||
proc evalImport(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var emptySet: TIntSet
|
||||
var emptySet: IntSet
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = myImportModule(c, n.sons[i])
|
||||
if m != nil:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -33,7 +33,7 @@ import
|
|||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
||||
intsets, cgmeth
|
||||
intsets, cgmeth, lowerings
|
||||
|
||||
type
|
||||
TTarget = enum
|
||||
|
|
@ -71,8 +71,8 @@ type
|
|||
TGlobals = object
|
||||
typeInfo, code: PRope
|
||||
forwarded: seq[PSym]
|
||||
generatedSyms: TIntSet
|
||||
typeInfoGenerated: TIntSet
|
||||
generatedSyms: IntSet
|
||||
typeInfoGenerated: IntSet
|
||||
|
||||
PGlobals = ref TGlobals
|
||||
PProc = ref TProc
|
||||
|
|
@ -113,7 +113,7 @@ proc rdLoc(a: TCompRes): PRope {.inline.} =
|
|||
result = ropef("$1[$2]", a.address, a.res)
|
||||
|
||||
proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||
options: TOptions): PProc =
|
||||
options: TOptions): PProc =
|
||||
result = PProc(
|
||||
blocks: @[],
|
||||
options: options,
|
||||
|
|
@ -601,15 +601,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if p.target == targetJS:
|
||||
app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
gen(p, n.sons[i].sons[0], a)
|
||||
moveInto(p, a, r)
|
||||
genStmt(p, n.sons[i].sons[0])
|
||||
if p.target == targetJS:
|
||||
app(p.body, "}" & tnl)
|
||||
if p.target == targetLua:
|
||||
# we need to repeat the finally block for Lua ...
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
gen(p, n.sons[i].sons[0], a)
|
||||
moveInto(p, a, r)
|
||||
genStmt(p, n.sons[i].sons[0])
|
||||
|
||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
genLineDir(p, n)
|
||||
|
|
@ -724,7 +722,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
|||
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
|
||||
var sym = n.sons[0].sym
|
||||
sym.loc.k = locOther
|
||||
sym.loc.a = idx
|
||||
sym.position = idx+1
|
||||
setLen(p.blocks, idx + 1)
|
||||
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
||||
let labl = p.unique
|
||||
|
|
@ -741,7 +739,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
|||
assert(n.sons[0].kind == nkSym)
|
||||
let sym = n.sons[0].sym
|
||||
assert(sym.loc.k == locOther)
|
||||
idx = sym.loc.a
|
||||
idx = sym.position-1
|
||||
else:
|
||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||
idx = len(p.blocks) - 1
|
||||
|
|
@ -942,22 +940,21 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
case s.kind
|
||||
of skVar, skLet, skResult:
|
||||
r.kind = resExpr
|
||||
if mapType(n.typ) == etyObject:
|
||||
if mapType(n.sons[0].typ) == etyObject:
|
||||
# make addr() a no-op:
|
||||
r.typ = etyNone
|
||||
r.res = s.loc.r
|
||||
r.address = nil
|
||||
elif sfGlobal in s.flags:
|
||||
# globals are always indirect accessible
|
||||
r.typ = etyBaseIndex
|
||||
r.address = toRope("Globals")
|
||||
r.res = makeJSString(ropeToStr(s.loc.r))
|
||||
elif sfAddrTaken in s.flags:
|
||||
elif {sfGlobal, sfAddrTaken} * s.flags != {}:
|
||||
# for ease of code generation, we do not distinguish between
|
||||
# sfAddrTaken and sfGlobal.
|
||||
r.typ = etyBaseIndex
|
||||
r.address = s.loc.r
|
||||
r.res = toRope("0")
|
||||
else:
|
||||
internalError(n.info, "genAddr: 4")
|
||||
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||
gen(p, n.sons[0], r)
|
||||
#internalError(n.info, "genAddr: 4 " & renderTree(n))
|
||||
else: internalError(n.info, "genAddr: 2")
|
||||
of nkCheckedFieldExpr:
|
||||
genCheckedFieldAddr(p, n, r)
|
||||
|
|
@ -981,7 +978,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
|||
of skVar, skLet, skParam, skTemp, skResult:
|
||||
if s.loc.r == nil:
|
||||
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||
var k = mapType(s.typ)
|
||||
let k = mapType(s.typ)
|
||||
if k == etyBaseIndex:
|
||||
r.typ = etyBaseIndex
|
||||
if {sfAddrTaken, sfGlobal} * s.flags != {}:
|
||||
|
|
@ -990,7 +987,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
|||
else:
|
||||
r.address = s.loc.r
|
||||
r.res = con(s.loc.r, "_Idx")
|
||||
elif k != etyObject and sfAddrTaken in s.flags:
|
||||
elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
|
||||
r.res = ropef("$1[0]", [s.loc.r])
|
||||
else:
|
||||
r.res = s.loc.r
|
||||
|
|
@ -1078,8 +1075,16 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
|||
|
||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "rawEcho")
|
||||
app(r.res, "rawEcho")
|
||||
genArgs(p, n, r)
|
||||
app(r.res, "rawEcho(")
|
||||
let n = n[1].skipConv
|
||||
internalAssert n.kind == nkBracket
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
if it.typ.isCompileTimeOnly: continue
|
||||
if i > 0: app(r.res, ", ")
|
||||
genArg(p, it, r)
|
||||
app(r.res, ")")
|
||||
r.kind = resExpr
|
||||
|
||||
proc putToSeq(s: string, indirect: bool): PRope =
|
||||
result = toRope(s)
|
||||
|
|
@ -1162,8 +1167,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
|
|||
internalError("createVar: " & $t.kind)
|
||||
result = nil
|
||||
|
||||
proc isIndirect(v: PSym): bool =
|
||||
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
|
||||
proc isIndirect(v: PSym): bool =
|
||||
result = {sfAddrTaken, sfGlobal} * v.flags != {} and
|
||||
(mapType(v.typ) != etyObject) and
|
||||
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
|
||||
|
||||
proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
|
|
@ -1203,13 +1209,17 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
|||
proc genVarStmt(p: PProc, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
assert(a.kind == nkIdentDefs)
|
||||
assert(a.sons[0].kind == nkSym)
|
||||
var v = a.sons[0].sym
|
||||
if lfNoDecl in v.loc.flags: continue
|
||||
genLineDir(p, a)
|
||||
genVarInit(p, v, a.sons[2])
|
||||
if a.kind != nkCommentStmt:
|
||||
if a.kind == nkVarTuple:
|
||||
let unpacked = lowerTupleUnpacking(a, p.prc)
|
||||
genStmt(p, unpacked)
|
||||
else:
|
||||
assert(a.kind == nkIdentDefs)
|
||||
assert(a.sons[0].kind == nkSym)
|
||||
var v = a.sons[0].sym
|
||||
if lfNoDecl notin v.loc.flags:
|
||||
genLineDir(p, a)
|
||||
genVarInit(p, v, a.sons[2])
|
||||
|
||||
proc genConstant(p: PProc, c: PSym) =
|
||||
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
|
||||
|
|
@ -1425,7 +1435,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
|||
r.res = toRope("{")
|
||||
r.kind = resExpr
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i > 0: app(r.res, ", ")
|
||||
if i > 1: app(r.res, ", ")
|
||||
var it = n.sons[i]
|
||||
internalAssert it.kind == nkExprColonExpr
|
||||
gen(p, it.sons[1], a)
|
||||
|
|
@ -1654,6 +1664,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
|||
r.res = nil
|
||||
of nkGotoState, nkState:
|
||||
internalError(n.info, "first class iterators not implemented")
|
||||
of nkPragmaBlock: gen(p, n.lastSon, r)
|
||||
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
|
||||
|
||||
var globals: PGlobals
|
||||
|
|
@ -1664,11 +1675,11 @@ proc newModule(module: PSym): BModule =
|
|||
if globals == nil: globals = newGlobals()
|
||||
|
||||
proc genHeader(): PRope =
|
||||
result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
|
||||
result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
|
||||
"/* (c) 2014 Andreas Rumpf */$n$n" &
|
||||
"$nvar Globals = this;$n" &
|
||||
"var framePtr = null;$n" &
|
||||
"var excHandler = null;$n",
|
||||
"var excHandler = null;$n" &
|
||||
"var lastJSError = null;$n",
|
||||
[toRope(VersionAsString)])
|
||||
|
||||
proc genModule(p: PProc, n: PNode) =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -128,7 +128,7 @@ type
|
|||
obj: PType
|
||||
|
||||
PEnv = ref TEnv
|
||||
TEnv {.final.} = object of TObject
|
||||
TEnv {.final.} = object of RootObj
|
||||
attachedNode, replacementNode: PNode
|
||||
createdVar: PNode # if != nil it is a used environment; for closure
|
||||
# iterators this can be 'envParam.env'
|
||||
|
|
@ -140,12 +140,12 @@ type
|
|||
fn: PSym # function that belongs to this scope;
|
||||
# if up.fn != fn then we cross function boundaries.
|
||||
# This is an important case to consider.
|
||||
vars: TIntSet # variables belonging to this environment
|
||||
vars: IntSet # variables belonging to this environment
|
||||
|
||||
TOuterContext = object
|
||||
fn: PSym # may also be a module!
|
||||
head: PEnv
|
||||
capturedVars, processed: TIntSet
|
||||
capturedVars, processed: IntSet
|
||||
localsToAccess: TIdNodeTable
|
||||
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -21,10 +21,10 @@ import
|
|||
|
||||
const
|
||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||
OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
|
||||
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||
OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
|
||||
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
|
||||
|
||||
# don't forget to update the 'highlite' module if these charsets should change
|
||||
|
|
@ -35,9 +35,10 @@ type
|
|||
tkSymbol, # keywords:
|
||||
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
|
||||
tkBind, tkBlock, tkBreak, tkCase, tkCast,
|
||||
tkConst, tkContinue, tkConverter, tkDiscard, tkDistinct, tkDiv, tkDo,
|
||||
tkConst, tkContinue, tkConverter,
|
||||
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
|
||||
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
|
||||
tkFinally, tkFor, tkFrom,
|
||||
tkFinally, tkFor, tkFrom, tkFunc,
|
||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||
tkIs, tkIsnot, tkIterator,
|
||||
tkLet,
|
||||
|
|
@ -71,11 +72,12 @@ const
|
|||
"tkSymbol",
|
||||
"addr", "and", "as", "asm", "atomic",
|
||||
"bind", "block", "break", "case", "cast",
|
||||
"const", "continue", "converter", "discard", "distinct", "div", "do",
|
||||
"const", "continue", "converter",
|
||||
"defer", "discard", "distinct", "div", "do",
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "generic", "if",
|
||||
"finally", "for", "from", "func", "generic", "if",
|
||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||
"let",
|
||||
"let",
|
||||
"macro", "method", "mixin", "mod",
|
||||
"nil", "not", "notin", "object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
|
|
@ -102,7 +104,7 @@ type
|
|||
# so that it is the correct default value
|
||||
base2, base8, base16
|
||||
|
||||
TToken* = object # a Nimrod token
|
||||
TToken* = object # a Nim token
|
||||
tokType*: TTokType # the type of the token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
# preceeded with indentation
|
||||
|
|
@ -116,7 +118,8 @@ type
|
|||
literal*: string # the parsed (string) literal; and
|
||||
# documentation comments are here too
|
||||
line*, col*: int
|
||||
|
||||
|
||||
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
|
||||
TLexer* = object of TBaseLexer
|
||||
fileIdx*: int32
|
||||
indentAhead*: int # if > 0 an indendation has already been read
|
||||
|
|
@ -124,7 +127,7 @@ type
|
|||
# needs so much look-ahead
|
||||
currLineIndent*: int
|
||||
strongSpaces*: bool
|
||||
|
||||
errorHandler*: TErrorHandler
|
||||
|
||||
var gLinesCompiled*: int # all lines that have been compiled
|
||||
|
||||
|
|
@ -148,7 +151,7 @@ proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
|
|||
proc isKeyword(kind: TTokType): bool =
|
||||
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
|
||||
|
||||
proc isNimrodIdentifier*(s: string): bool =
|
||||
proc isNimIdentifier*(s: string): bool =
|
||||
if s[0] in SymStartChars:
|
||||
var i = 1
|
||||
while i < s.len:
|
||||
|
|
@ -222,14 +225,20 @@ proc getColumn(L: TLexer): int =
|
|||
proc getLineInfo(L: TLexer): TLineInfo =
|
||||
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
||||
|
||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
msgs.message(getLineInfo(L), msg, arg)
|
||||
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
if L.errorHandler.isNil:
|
||||
msgs.message(info, msg, arg)
|
||||
else:
|
||||
L.errorHandler(info, msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||
L.dispMessage(getLineInfo(L), msg, arg)
|
||||
|
||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
|
||||
msgs.message(info, msg, arg)
|
||||
L.dispMessage(info, msg, arg)
|
||||
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
|
||||
var pos = L.bufpos # use registers for pos, buf
|
||||
var buf = L.buf
|
||||
while true:
|
||||
|
|
@ -246,7 +255,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
|||
inc(pos)
|
||||
L.bufpos = pos
|
||||
|
||||
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
|
||||
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||
|
||||
proc isFloatLiteral(s: string): bool =
|
||||
|
|
@ -429,9 +438,9 @@ proc getNumber(L: var TLexer): TToken =
|
|||
elif result.tokType == tkInt16Lit and
|
||||
(result.iNumber < int16.low or result.iNumber > int16.high):
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
except EInvalidValue:
|
||||
except ValueError:
|
||||
lexMessage(L, errInvalidNumber, result.literal)
|
||||
except EOverflow, EOutOfRange:
|
||||
except OverflowError, RangeError:
|
||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||
L.bufpos = endpos
|
||||
|
||||
|
|
@ -482,7 +491,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
|||
add(tok.literal, VT)
|
||||
inc(L.bufpos)
|
||||
of 't', 'T':
|
||||
add(tok.literal, Tabulator)
|
||||
add(tok.literal, '\t')
|
||||
inc(L.bufpos)
|
||||
of '\'', '\"':
|
||||
add(tok.literal, L.buf[L.bufpos])
|
||||
|
|
@ -519,7 +528,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
|
|||
lexMessagePos(L, hintLineTooLong, pos)
|
||||
|
||||
if optEmbedOrigSrc in gGlobalOptions:
|
||||
let lineStart = cast[TAddress](L.buf) + L.lineStart
|
||||
let lineStart = cast[ByteAddress](L.buf) + L.lineStart
|
||||
let line = newString(cast[cstring](lineStart), col)
|
||||
addSourceLine(L.fileIdx, line)
|
||||
|
||||
|
|
@ -659,28 +668,32 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
|||
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tok.strongSpaceB = -1
|
||||
|
||||
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||
var pos = L.bufpos
|
||||
var buf = L.buf
|
||||
# a comment ends if the next line does not start with the # on the same
|
||||
# column after only whitespace
|
||||
var buf = L.buf
|
||||
when not defined(nimfix):
|
||||
assert buf[pos+1] == '#'
|
||||
if buf[pos+2] == '[':
|
||||
lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
|
||||
tok.tokType = tkComment
|
||||
# iNumber contains the number of '\n' in the token
|
||||
tok.iNumber = 0
|
||||
var col = getColNumber(L, pos)
|
||||
when defined(nimfix):
|
||||
var col = getColNumber(L, pos)
|
||||
while true:
|
||||
var lastBackslash = -1
|
||||
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
|
||||
if buf[pos] == '\\': lastBackslash = pos+1
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
if lastBackslash > 0:
|
||||
# a backslash is a continuation character if only followed by spaces
|
||||
# plus a newline:
|
||||
while buf[lastBackslash] == ' ': inc(lastBackslash)
|
||||
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
|
||||
# false positive:
|
||||
lastBackslash = -1
|
||||
when defined(nimfix):
|
||||
if lastBackslash > 0:
|
||||
# a backslash is a continuation character if only followed by spaces
|
||||
# plus a newline:
|
||||
while buf[lastBackslash] == ' ': inc(lastBackslash)
|
||||
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
|
||||
# false positive:
|
||||
lastBackslash = -1
|
||||
|
||||
pos = handleCRLF(L, pos)
|
||||
buf = L.buf
|
||||
|
|
@ -688,9 +701,16 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
|||
while buf[pos] == ' ':
|
||||
inc(pos)
|
||||
inc(indent)
|
||||
if buf[pos] == '#' and (col == indent or lastBackslash > 0):
|
||||
|
||||
when defined(nimfix):
|
||||
template doContinue(): expr =
|
||||
buf[pos] == '#' and (col == indent or lastBackslash > 0)
|
||||
else:
|
||||
template doContinue(): expr =
|
||||
buf[pos] == '#' and buf[pos+1] == '#'
|
||||
if doContinue():
|
||||
tok.literal.add "\n"
|
||||
col = indent
|
||||
when defined(nimfix): col = indent
|
||||
inc tok.iNumber
|
||||
else:
|
||||
if buf[pos] > ' ':
|
||||
|
|
@ -707,7 +727,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
|||
of ' ':
|
||||
inc(pos)
|
||||
inc(tok.strongSpaceA)
|
||||
of Tabulator:
|
||||
of '\t':
|
||||
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
||||
inc(pos)
|
||||
of CR, LF:
|
||||
|
|
@ -718,10 +738,24 @@ proc skip(L: var TLexer, tok: var TToken) =
|
|||
inc(pos)
|
||||
inc(indent)
|
||||
tok.strongSpaceA = 0
|
||||
if buf[pos] > ' ':
|
||||
when defined(nimfix):
|
||||
template doBreak(): expr = buf[pos] > ' '
|
||||
else:
|
||||
template doBreak(): expr =
|
||||
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
|
||||
if doBreak():
|
||||
tok.indent = indent
|
||||
L.currLineIndent = indent
|
||||
break
|
||||
of '#':
|
||||
when defined(nimfix):
|
||||
break
|
||||
else:
|
||||
# do not skip documentation comment:
|
||||
if buf[pos+1] == '#': break
|
||||
if buf[pos+1] == '[':
|
||||
lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['")
|
||||
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
L.bufpos = pos
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
import os
|
||||
type
|
||||
PListEntry* = ref TListEntry
|
||||
TListEntry* = object of TObject
|
||||
TListEntry* = object of RootObj
|
||||
prev*, next*: PListEntry
|
||||
|
||||
TStrEntry* = object of TListEntry
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -21,9 +21,9 @@ type
|
|||
llsString, # stream encapsulates a string
|
||||
llsFile, # stream encapsulates a file
|
||||
llsStdIn # stream encapsulates stdin
|
||||
TLLStream* = object of TObject
|
||||
TLLStream* = object of RootObj
|
||||
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
|
||||
f*: TFile
|
||||
f*: File
|
||||
s*: string
|
||||
rd*, wr*: int # for string streams
|
||||
lineOffset*: int # for fake stdin line numbers
|
||||
|
|
@ -31,8 +31,8 @@ type
|
|||
PLLStream* = ref TLLStream
|
||||
|
||||
proc llStreamOpen*(data: string): PLLStream
|
||||
proc llStreamOpen*(f: var TFile): PLLStream
|
||||
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
|
||||
proc llStreamOpen*(f: var File): PLLStream
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
|
||||
proc llStreamOpen*(): PLLStream
|
||||
proc llStreamOpenStdIn*(): PLLStream
|
||||
proc llStreamClose*(s: PLLStream)
|
||||
|
|
@ -50,12 +50,12 @@ proc llStreamOpen(data: string): PLLStream =
|
|||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc llStreamOpen(f: var TFile): PLLStream =
|
||||
proc llStreamOpen(f: var File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
||||
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
|
||||
proc llStreamOpen(filename: string, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
if not open(result.f, filename, mode): result = nil
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ type
|
|||
mode*: TOverloadIterMode
|
||||
symChoiceIndex*: int
|
||||
scope*: PScope
|
||||
inSymChoice: TIntSet
|
||||
inSymChoice: IntSet
|
||||
|
||||
proc getSymRepr*(s: PSym): string =
|
||||
case s.kind
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -51,13 +51,14 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
|||
incl(temp.flags, sfFromGeneric)
|
||||
|
||||
var v = newNodeI(nkVarSection, value.info)
|
||||
v.addVar(newSymNode(temp))
|
||||
let tempAsNode = newSymNode(temp)
|
||||
v.addVar(tempAsNode)
|
||||
result.add(v)
|
||||
|
||||
result.add newAsgnStmt(newSymNode(temp), value)
|
||||
result.add newAsgnStmt(tempAsNode, value)
|
||||
for i in 0 .. n.len-3:
|
||||
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
|
||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
|
||||
|
||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||
result = newType(tyObject, owner)
|
||||
|
|
@ -204,7 +205,7 @@ proc flowVarKind(t: PType): TFlowVarKind =
|
|||
else: fvBlob
|
||||
|
||||
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
||||
v: PNode): PSym =
|
||||
v: PNode; useShallowCopy=false): PSym =
|
||||
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
|
||||
result.typ = typ
|
||||
incl(result.flags, sfFromGeneric)
|
||||
|
|
@ -215,11 +216,14 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
|||
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
|
||||
varSection.add vpart
|
||||
if varInit != nil:
|
||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
||||
deepCopyCall.sons[1] = newSymNode(result)
|
||||
deepCopyCall.sons[2] = v
|
||||
varInit.add deepCopyCall
|
||||
if useShallowCopy:
|
||||
varInit.add newFastAsgnStmt(newSymNode(result), v)
|
||||
else:
|
||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
||||
deepCopyCall.sons[1] = newSymNode(result)
|
||||
deepCopyCall.sons[2] = v
|
||||
varInit.add deepCopyCall
|
||||
|
||||
discard """
|
||||
We generate roughly this:
|
||||
|
|
@ -261,7 +265,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
|||
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
|
||||
barrier.typ, barrier)
|
||||
body.add varSection2
|
||||
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
||||
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
||||
var threadLocalProm: PSym
|
||||
if spawnKind == srByVar:
|
||||
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
||||
|
|
@ -276,7 +280,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
|||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||
"owner", fv.info), threadParam.newSymNode)
|
||||
|
||||
body.add callCodeGenProc("nimArgsPassingDone", threadParam.newSymNode)
|
||||
body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
|
||||
if spawnKind == srByVar:
|
||||
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
|
||||
elif fv != nil:
|
||||
|
|
@ -286,14 +290,20 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
|||
typeToString(fv.typ.sons[1]))
|
||||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||
if fk == fvGC: "data" else: "blob", fv.info), call)
|
||||
if fk == fvGC:
|
||||
let incRefCall = newNodeI(nkCall, fv.info, 2)
|
||||
incRefCall.sons[0] = newSymNode(createMagic("GCref", mGCref))
|
||||
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
|
||||
"data", fv.info)
|
||||
body.add incRefCall
|
||||
if barrier == nil:
|
||||
# by now 'fv' is shared and thus might have beeen overwritten! we need
|
||||
# to use the thread-local view instead:
|
||||
body.add callCodeGenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
|
||||
body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
|
||||
else:
|
||||
body.add call
|
||||
if barrier != nil:
|
||||
body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode)
|
||||
body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
|
||||
|
||||
var params = newNodeI(nkFormalParams, f.info)
|
||||
params.add emptyNode
|
||||
|
|
@ -414,7 +424,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
|||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
||||
|
||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
|
||||
indirectAccess(castExpr, fieldA, n.info))
|
||||
indirectAccess(castExpr, fieldA, n.info),
|
||||
useShallowCopy=true)
|
||||
slice.sons[2] = threadLocal.newSymNode
|
||||
else:
|
||||
let a = genAddrOf(n)
|
||||
|
|
@ -428,7 +439,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
|||
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
||||
|
||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
|
||||
indirectAccess(castExpr, fieldB, n.info))
|
||||
indirectAccess(castExpr, fieldB, n.info),
|
||||
useShallowCopy=true)
|
||||
slice.sons[3] = threadLocal.newSymNode
|
||||
call.add slice
|
||||
elif (let size = computeSize(argType); size < 0 or size > 16) and
|
||||
|
|
@ -439,7 +451,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
|||
objType.addField(field)
|
||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
|
||||
indirectAccess(castExpr, field, n.info))
|
||||
indirectAccess(castExpr, field, n.info),
|
||||
useShallowCopy=true)
|
||||
call.add(genDeref(threadLocal.newSymNode))
|
||||
else:
|
||||
# boring case
|
||||
|
|
@ -448,7 +461,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
|||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
||||
let threadLocal = addLocalVar(varSection, varInit,
|
||||
objType.owner, field.typ,
|
||||
indirectAccess(castExpr, field, n.info))
|
||||
indirectAccess(castExpr, field, n.info),
|
||||
useShallowCopy=true)
|
||||
call.add(threadLocal.newSymNode)
|
||||
|
||||
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||
|
|
@ -543,7 +557,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
|||
# create flowVar:
|
||||
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
|
||||
if barrier == nil:
|
||||
result.add callCodeGenProc("nimFlowVarCreateCondVar", fvField)
|
||||
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
|
||||
|
||||
elif spawnKind == srByVar:
|
||||
var field = newSym(skField, getIdent"fv", owner, n.info)
|
||||
|
|
@ -556,7 +570,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
|||
let wrapper = createWrapperProc(fn, threadParam, argsParam,
|
||||
varSection, varInit, call,
|
||||
barrierAsExpr, fvAsExpr, spawnKind)
|
||||
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
||||
result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
|
||||
genAddrOf(scratchObj.newSymNode))
|
||||
|
||||
if spawnKind == srFlowVar: result.add fvField
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -35,7 +35,7 @@ proc registerSysType(t: PType) =
|
|||
proc newSysType(kind: TTypeKind, size: int): PType =
|
||||
result = newType(kind, systemModule)
|
||||
result.size = size
|
||||
result.align = size
|
||||
result.align = size.int16
|
||||
|
||||
proc getSysSym(name: string): PSym =
|
||||
result = strTableGet(systemModule.tab, getIdent(name))
|
||||
|
|
@ -44,6 +44,7 @@ proc getSysSym(name: string): PSym =
|
|||
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||
var ti: TIdentIter
|
||||
|
|
@ -165,13 +166,14 @@ proc setIntLitType*(result: PNode) =
|
|||
proc getCompilerProc(name: string): PSym =
|
||||
var ident = getIdent(name, hashIgnoreStyle(name))
|
||||
result = strTableGet(compilerprocs, ident)
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
result = strTableGet(rodCompilerprocs, ident)
|
||||
if result != nil:
|
||||
if result != nil:
|
||||
strTableAdd(compilerprocs, result)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
|
||||
proc registerCompilerProc(s: PSym) =
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc registerCompilerProc(s: PSym) =
|
||||
strTableAdd(compilerprocs, s)
|
||||
|
||||
proc finishSystem(tab: TStrTable) = discard
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -15,8 +15,7 @@ import
|
|||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||
cgen, jsgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
|
||||
pretty
|
||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||
|
||||
from magicsys import systemModule, resetSysTypes
|
||||
|
||||
|
|
@ -164,19 +163,6 @@ proc commandEval(exp: string) =
|
|||
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
||||
evalNim(echoExp.parseString, makeStdinModule())
|
||||
|
||||
proc commandPrettyOld =
|
||||
var projectFile = addFileExt(mainCommandArg(), NimExt)
|
||||
var module = parseFile(projectFile.fileInfoIdx)
|
||||
if module != nil:
|
||||
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
||||
|
||||
proc commandPretty =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
semanticPasses()
|
||||
registerPass(prettyPass)
|
||||
compileProject()
|
||||
pretty.overwriteFiles()
|
||||
|
||||
proc commandScan =
|
||||
var f = addFileExt(mainCommandArg(), NimExt)
|
||||
var stream = llStreamOpen(f, fmRead)
|
||||
|
|
@ -217,25 +203,6 @@ proc commandSuggest =
|
|||
else: gProjectMainIdx
|
||||
compileProject(projFile)
|
||||
|
||||
proc wantMainModule =
|
||||
if gProjectFull.len == 0:
|
||||
if optMainModule.len == 0:
|
||||
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||
else:
|
||||
gProjectName = optMainModule
|
||||
gProjectFull = gProjectPath / gProjectName
|
||||
|
||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||
|
||||
proc requireMainModuleOption =
|
||||
if optMainModule.len == 0:
|
||||
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
|
||||
else:
|
||||
gProjectName = optMainModule
|
||||
gProjectFull = gProjectPath / gProjectName
|
||||
|
||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||
|
||||
proc resetMemory =
|
||||
resetCompilationLists()
|
||||
ccgutils.resetCaches()
|
||||
|
|
@ -299,30 +266,22 @@ proc mainCommand* =
|
|||
# current path is always looked first for modules
|
||||
prependStr(searchPaths, gProjectPath)
|
||||
setId(100)
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
case command.normalize
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
# compile means compileToC currently
|
||||
gCmd = cmdCompileToC
|
||||
wantMainModule()
|
||||
commandCompileToC()
|
||||
of "cpp", "compiletocpp":
|
||||
extccomp.cExt = ".cpp"
|
||||
gCmd = cmdCompileToCpp
|
||||
if cCompiler == ccGcc: setCC("gcc")
|
||||
wantMainModule()
|
||||
defineSymbol("cpp")
|
||||
commandCompileToC()
|
||||
of "objc", "compiletooc":
|
||||
extccomp.cExt = ".m"
|
||||
gCmd = cmdCompileToOC
|
||||
wantMainModule()
|
||||
defineSymbol("objc")
|
||||
commandCompileToC()
|
||||
of "run":
|
||||
gCmd = cmdRun
|
||||
wantMainModule()
|
||||
when hasTinyCBackend:
|
||||
extccomp.setCC("tcc")
|
||||
commandCompileToC()
|
||||
|
|
@ -330,41 +289,33 @@ proc mainCommand* =
|
|||
rawMessage(errInvalidCommandX, command)
|
||||
of "js", "compiletojs":
|
||||
gCmd = cmdCompileToJS
|
||||
wantMainModule()
|
||||
commandCompileToJS()
|
||||
of "compiletollvm":
|
||||
gCmd = cmdCompileToLLVM
|
||||
wantMainModule()
|
||||
when hasLLVM_Backend:
|
||||
CommandCompileToLLVM()
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, command)
|
||||
of "pretty":
|
||||
gCmd = cmdPretty
|
||||
wantMainModule()
|
||||
commandPretty()
|
||||
of "doc":
|
||||
wantMainModule()
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
commandDoc()
|
||||
of "doc2":
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
defineSymbol("nimdoc")
|
||||
commandDoc2()
|
||||
of "rst2html":
|
||||
gCmd = cmdRst2html
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
commandRst2Html()
|
||||
of "rst2tex":
|
||||
gCmd = cmdRst2tex
|
||||
loadConfigs(DocTexConfig)
|
||||
wantMainModule()
|
||||
commandRst2TeX()
|
||||
of "jsondoc":
|
||||
wantMainModule()
|
||||
gCmd = cmdDoc
|
||||
loadConfigs(DocConfig)
|
||||
wantMainModule()
|
||||
|
|
@ -376,12 +327,11 @@ proc mainCommand* =
|
|||
commandBuildIndex()
|
||||
of "gendepend":
|
||||
gCmd = cmdGenDepend
|
||||
wantMainModule()
|
||||
commandGenDepend()
|
||||
of "dump":
|
||||
gCmd = cmdDump
|
||||
if getConfigVar("dump.format") == "json":
|
||||
requireMainModuleOption()
|
||||
wantMainModule()
|
||||
|
||||
var definedSymbols = newJArray()
|
||||
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
|
||||
|
|
@ -405,7 +355,6 @@ proc mainCommand* =
|
|||
for it in iterSearchPath(searchPaths): msgWriteln(it)
|
||||
of "check":
|
||||
gCmd = cmdCheck
|
||||
wantMainModule()
|
||||
commandCheck()
|
||||
of "parse":
|
||||
gCmd = cmdParse
|
||||
|
|
@ -429,7 +378,6 @@ proc mainCommand* =
|
|||
if gEvalExpr != "":
|
||||
commandEval(gEvalExpr)
|
||||
else:
|
||||
wantMainModule()
|
||||
commandSuggest()
|
||||
of "serve":
|
||||
isServing = true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -117,7 +117,7 @@ proc newModule(fileIdx: int32): PSym =
|
|||
result.kind = skModule
|
||||
let filename = fileIdx.toFullPath
|
||||
result.name = getIdent(splitFile(filename).name)
|
||||
if not isNimrodIdentifier(result.name.s):
|
||||
if not isNimIdentifier(result.name.s):
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
|
|
@ -177,7 +177,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
|||
proc `==^`(a, b: string): bool =
|
||||
try:
|
||||
result = sameFile(a, b)
|
||||
except EOS:
|
||||
except OSError:
|
||||
result = false
|
||||
|
||||
proc compileSystemModule* =
|
||||
|
|
@ -185,8 +185,18 @@ proc compileSystemModule* =
|
|||
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||
discard compileModule(systemFileIdx, {sfSystemModule})
|
||||
|
||||
proc compileProject*(projectFile = gProjectMainIdx) =
|
||||
proc wantMainModule* =
|
||||
if gProjectFull.len == 0:
|
||||
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
|
||||
proc compileProject*(projectFileIdx = -1'i32) =
|
||||
wantMainModule()
|
||||
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
||||
let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
|
||||
if projectFile == systemFileIdx:
|
||||
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -114,17 +114,18 @@ type
|
|||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
warnDeprecated, warnConfigDeprecated,
|
||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnNilStatement, warnAnalysisLoophole,
|
||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnUser,
|
||||
warnUninit, warnGcMem, warnLockLevel, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintPattern,
|
||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintUser
|
||||
|
||||
const
|
||||
|
|
@ -368,13 +369,14 @@ const
|
|||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
|
||||
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
|
||||
warnDeprecated: "\'$1\' is deprecated [Deprecated]",
|
||||
warnDeprecated: "$1 is deprecated [Deprecated]",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
|
||||
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
|
||||
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
|
||||
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
|
||||
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
|
||||
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
|
||||
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
|
||||
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
|
||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
|
||||
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
|
||||
|
|
@ -387,9 +389,10 @@ const
|
|||
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
||||
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
||||
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
||||
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
|
||||
warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
|
||||
warnUninit: "'$1' might not have been initialized [Uninit]",
|
||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||
warnLockLevel: "$1 [LockLevel]",
|
||||
warnUser: "$1 [User]",
|
||||
hintSuccess: "operation successful [Success]",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||
|
|
@ -405,25 +408,27 @@ const
|
|||
hintConf: "used config file \'$1\' [Conf]",
|
||||
hintPath: "added path: '$1' [Path]",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
|
||||
hintName: "name should be: '$1' [Name]",
|
||||
hintPattern: "$1 [Pattern]",
|
||||
hintUser: "$1 [User]"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
|
||||
WarningsToStr*: array[0..28, string] = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored", "NilStmt",
|
||||
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "User"]
|
||||
"GcMem", "LockLevel", "User"]
|
||||
|
||||
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Pattern",
|
||||
"Path", "CondTrue", "Name", "Pattern",
|
||||
"User"]
|
||||
|
||||
const
|
||||
|
|
@ -441,11 +446,11 @@ type
|
|||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
TFileInfo*{.final.} = object
|
||||
fullPath*: string # This is a canonical full filesystem path
|
||||
fullPath: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
quotedName*: PRope # cached quoted short name for codegen
|
||||
# purpoes
|
||||
# purposes
|
||||
|
||||
lines*: seq[PRope] # the source code of the module
|
||||
# used for better error messages and
|
||||
|
|
@ -468,8 +473,8 @@ type
|
|||
|
||||
TErrorOutputs* = set[TErrorOutput]
|
||||
|
||||
ERecoverableError* = object of EInvalidValue
|
||||
ESuggestDone* = object of E_Base
|
||||
ERecoverableError* = object of ValueError
|
||||
ESuggestDone* = object of Exception
|
||||
|
||||
const
|
||||
InvalidFileIDX* = int32(-1)
|
||||
|
|
@ -567,7 +572,7 @@ var
|
|||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||
|
||||
when useCaas:
|
||||
var stdoutSocket*: TSocket
|
||||
var stdoutSocket*: Socket
|
||||
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = int16(-1)
|
||||
|
|
@ -784,6 +789,14 @@ proc writeSurroundingSrc(info: TLineInfo) =
|
|||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let frmt = case msg
|
||||
of warnMin..warnMax: PosWarningFormat
|
||||
of hintMin..hintMax: PosHintFormat
|
||||
else: PosErrorFormat
|
||||
result = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||
coordToStr(info.col), getMessageStr(msg, arg)]
|
||||
|
||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling) =
|
||||
var frmt: string
|
||||
|
|
@ -858,7 +871,7 @@ proc sourceLine*(i: TLineInfo): PRope =
|
|||
try:
|
||||
for line in lines(i.toFullPath):
|
||||
addSourceLine i.fileIndex, line.string
|
||||
except EIO:
|
||||
except IOError:
|
||||
discard
|
||||
internalAssert i.fileIndex < fileInfos.len
|
||||
# can happen if the error points to EOF:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
; and project.
|
||||
|
||||
[Project]
|
||||
Name: "Nimrod"
|
||||
Name: "Nim"
|
||||
Version: "$version"
|
||||
Platforms: """
|
||||
windows: i386;amd64
|
||||
|
|
@ -16,15 +16,15 @@ Platforms: """
|
|||
"""
|
||||
|
||||
Authors: "Andreas Rumpf"
|
||||
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
|
||||
Description: """This is the Nim Compiler. Nim is a new statically typed,
|
||||
imperative programming language, that supports procedural, functional, object
|
||||
oriented and generic programming styles while remaining simple and efficient.
|
||||
A special feature that Nimrod inherited from Lisp is that Nimrod's abstract
|
||||
A special feature that Nim inherited from Lisp is that Nim's abstract
|
||||
syntax tree (AST) is part of the specification - this allows a powerful macro
|
||||
system which can be used to create domain specific languages.
|
||||
|
||||
Nimrod is a compiled, garbage-collected systems programming language
|
||||
which has an excellent productivity/performance ratio. Nimrod's design
|
||||
Nim is a compiled, garbage-collected systems programming language
|
||||
which has an excellent productivity/performance ratio. Nim's design
|
||||
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
|
||||
priority)."""
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ App: Console
|
|||
License: "copying.txt"
|
||||
|
||||
[Config]
|
||||
Files: "config/nimrod.cfg"
|
||||
Files: "config/nim.cfg"
|
||||
Files: "config/nimdoc.cfg"
|
||||
Files: "config/nimdoc.tex.cfg"
|
||||
|
||||
|
|
@ -61,8 +61,8 @@ Files: "icons/koch.res"
|
|||
Files: "icons/koch_icon.o"
|
||||
|
||||
Files: "compiler/readme.txt"
|
||||
Files: "compiler/nimrod.ini"
|
||||
Files: "compiler/nimrod.cfg"
|
||||
Files: "compiler/nim.ini"
|
||||
Files: "compiler/nim.nimrod.cfg"
|
||||
Files: "compiler/*.nim"
|
||||
Files: "doc/*.txt"
|
||||
Files: "compiler/nimfix/*.nim"
|
||||
|
|
@ -113,10 +113,9 @@ Files: "examples/*.tmpl"
|
|||
|
||||
|
||||
[Windows]
|
||||
Files: "bin/nimrod.exe"
|
||||
Files: "bin/nimrod_debug.exe"
|
||||
Files: "bin/nim.exe"
|
||||
Files: "bin/nim_debug.exe"
|
||||
Files: "bin/c2nim.exe"
|
||||
Files: "bin/niminst.exe"
|
||||
Files: "bin/nimgrep.exe"
|
||||
|
||||
Files: "dist/*.dll"
|
||||
|
|
@ -132,7 +131,7 @@ Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia
|
|||
; for now only NSIS supports optional downloads
|
||||
|
||||
[UnixBin]
|
||||
Files: "bin/nimrod"
|
||||
Files: "bin/nim"
|
||||
|
||||
|
||||
[Unix]
|
||||
|
|
@ -156,6 +155,5 @@ flags = "-w"
|
|||
[deb]
|
||||
buildDepends: "gcc (>= 4:4.3.2)"
|
||||
pkgDepends: "gcc (>= 4:4.3.2)"
|
||||
shortDesc: "The Nimrod Compiler"
|
||||
licenses: "bin/nimrod,MIT;lib/*,MIT;"
|
||||
|
||||
shortDesc: "The Nim Compiler"
|
||||
licenses: "bin/nim,MIT;lib/*,MIT;"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -40,7 +40,7 @@ proc handleCmdLine() =
|
|||
if gProjectName != "":
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except EOS:
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
|
|
@ -58,7 +58,7 @@ proc handleCmdLine() =
|
|||
if msgs.gErrorCounter == 0:
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
tccgen.run(service.arguments)
|
||||
tccgen.run(commands.arguments)
|
||||
if optRun in gGlobalOptions:
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex: string
|
||||
|
|
@ -67,7 +67,7 @@ proc handleCmdLine() =
|
|||
else:
|
||||
ex = quoteShell(
|
||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||
execExternalProgram("node " & ex & ' ' & service.arguments)
|
||||
execExternalProgram("node " & ex & ' ' & commands.arguments)
|
||||
else:
|
||||
var binPath: string
|
||||
if options.outFile.len > 0:
|
||||
|
|
@ -77,7 +77,7 @@ proc handleCmdLine() =
|
|||
# Figure out ourselves a valid binary name.
|
||||
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
|
||||
var ex = quoteShell(binPath)
|
||||
execExternalProgram(ex & ' ' & service.arguments)
|
||||
execExternalProgram(ex & ' ' & commands.arguments)
|
||||
|
||||
when declared(GC_setMaxPause):
|
||||
GC_setMaxPause 2_000
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
# Special configuration file for the Nimrod project
|
||||
|
||||
mainModule:"nimrod.nim"
|
||||
# Special configuration file for the Nim project
|
||||
|
||||
# gc:markAndSweep
|
||||
|
||||
|
|
@ -21,3 +19,4 @@ define:useStdoutAsStdmsg
|
|||
|
||||
cs:partial
|
||||
#define:useNodeIds
|
||||
symbol:nimfix
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Implements some helper procs for Babel (Nimrod's package manager) support.
|
||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||
|
||||
import parseutils, strutils, strtabs, os, options, msgs, lists
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool =
|
|||
if a[i] == '.': inc i
|
||||
if b[j] == '.': inc j
|
||||
|
||||
proc addPackage(packages: PStringTable, p: string) =
|
||||
proc addPackage(packages: StringTableRef, p: string) =
|
||||
let x = versionSplitPos(p)
|
||||
let name = p.substr(0, x-1)
|
||||
if x < p.len:
|
||||
|
|
@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) =
|
|||
else:
|
||||
packages[name] = latest
|
||||
|
||||
iterator chosen(packages: PStringTable): string =
|
||||
iterator chosen(packages: StringTableRef): string =
|
||||
for key, val in pairs(packages):
|
||||
let res = if val == latest: key else: key & '-' & val
|
||||
yield res
|
||||
|
||||
proc addBabelPath(p: string, info: TLineInfo) =
|
||||
proc addNimblePath(p: string, info: TLineInfo) =
|
||||
if not contains(options.searchPaths, p):
|
||||
if gVerbosity >= 1: message(info, hintPath, p)
|
||||
lists.prependStr(options.lazyPaths, p)
|
||||
|
|
@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
|||
result = true
|
||||
break
|
||||
if hasNimFile(p):
|
||||
addBabelPath(p, info)
|
||||
addNimblePath(p, info)
|
||||
else:
|
||||
for kind, p2 in walkDir(p):
|
||||
if hasNimFile(p2): addBabelPath(p2, info)
|
||||
if hasNimFile(p2): addNimblePath(p2, info)
|
||||
|
||||
proc addPathRec(dir: string, info: TLineInfo) =
|
||||
var packages = newStringTable(modeStyleInsensitive)
|
||||
|
|
@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) =
|
|||
if k == pcDir and p[pos] != '.':
|
||||
addPackage(packages, p)
|
||||
for p in packages.chosen:
|
||||
addBabelPath(p, info)
|
||||
addNimblePath(p, info)
|
||||
|
||||
proc babelPath*(path: string, info: TLineInfo) =
|
||||
proc nimblePath*(path: string, info: TLineInfo) =
|
||||
addPathRec(path, info)
|
||||
addBabelPath(path, info)
|
||||
addNimblePath(path, info)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -14,7 +14,7 @@ import
|
|||
options, idents, wordrecg
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
# we use Nimrod's scanner here to safe space and work
|
||||
# we use Nim's scanner here to safe space and work
|
||||
|
||||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||
# simple filter
|
||||
|
|
@ -113,7 +113,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
|||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
setLen(condStack, len(condStack) + 1)
|
||||
var res = evalppIf(L, tok)
|
||||
let res = evalppIf(L, tok)
|
||||
condStack[high(condStack)] = res
|
||||
if not res: jumpToDirective(L, tok, jdElseEndif)
|
||||
of wElif: doElif(L, tok)
|
||||
|
|
@ -224,8 +224,10 @@ proc loadConfigs*(cfg: string) =
|
|||
if libpath == "":
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir()
|
||||
if prefix == "/usr": libpath = "/usr/lib/nimrod"
|
||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod"
|
||||
when defined(posix):
|
||||
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
|
||||
if optSkipConfigFile notin gGlobalOptions:
|
||||
|
|
@ -244,5 +246,6 @@ proc loadConfigs*(cfg: string) =
|
|||
|
||||
if gProjectName.len != 0:
|
||||
# new project wide config file:
|
||||
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
||||
|
||||
let projectConfig = changeFileExt(gProjectFull, "nim.cfg")
|
||||
if fileExists(projectConfig): readConfigFile(projectConfig)
|
||||
else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## exposes the Nimrod VM to clients.
|
||||
## exposes the Nim VM to clients.
|
||||
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
|
|||
const Usage = """
|
||||
Nimfix - Tool to patch Nim code
|
||||
Usage:
|
||||
nimfix [options] projectflie.nim
|
||||
nimfix [options] projectfile.nim
|
||||
|
||||
Options:
|
||||
--overwriteFiles:on|off overwrite the original nim files.
|
||||
|
|
@ -26,12 +26,13 @@ Options:
|
|||
--styleCheck:on|off|auto performs style checking for identifiers
|
||||
and suggests an alternative spelling;
|
||||
'auto' corrects the spelling.
|
||||
--bestEffort try to fix the code even when there
|
||||
are errors.
|
||||
|
||||
In addition, all command line options of Nim are supported.
|
||||
"""
|
||||
|
||||
proc mainCommand =
|
||||
#msgs.gErrorMax = high(int) # do not stop after first error
|
||||
registerPass verbosePass
|
||||
registerPass semPass
|
||||
gCmd = cmdPretty
|
||||
|
|
@ -63,13 +64,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
|||
of "on": gCheckExtern = true
|
||||
of "off": gCheckExtern = false
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "stylecheck":
|
||||
of "stylecheck":
|
||||
case p.val.normalize
|
||||
of "off": gStyleCheck = StyleCheck.None
|
||||
of "on": gStyleCheck = StyleCheck.Warn
|
||||
of "auto": gStyleCheck = StyleCheck.Auto
|
||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||
of "wholeproject": gOnlyMainfile = false
|
||||
of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error
|
||||
else:
|
||||
processSwitch(pass, p)
|
||||
of cmdArgument:
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ proc loadFile*(info: TLineInfo) =
|
|||
for line in lines(path):
|
||||
gSourceFiles[i].lines.add(line)
|
||||
# extract line ending of the file:
|
||||
var lex: TBaseLexer
|
||||
var lex: BaseLexer
|
||||
open(lex, newFileStream(path, fmRead))
|
||||
var pos = lex.bufpos
|
||||
while true:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -37,7 +37,7 @@ const
|
|||
NewLines* = {CR, LF}
|
||||
|
||||
type
|
||||
TBaseLexer* = object of TObject
|
||||
TBaseLexer* = object of RootObj
|
||||
bufpos*: int
|
||||
buf*: cstring
|
||||
bufLen*: int # length of buffer in characters
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# this unit handles Nimrod sets; it implements symbolic sets
|
||||
# this unit handles Nim sets; it implements symbolic sets
|
||||
|
||||
import
|
||||
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module contains Nimrod's version. It is the only place where it needs
|
||||
# This module contains Nim's version. It is the only place where it needs
|
||||
# to be changed.
|
||||
|
||||
const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
VersionMajor* = 0
|
||||
VersionMinor* = 9
|
||||
VersionPatch* = 7
|
||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -68,7 +68,7 @@ type # please make sure we have under 32 options
|
|||
# also: generate header file
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
TCommands* = enum # Nimrod's commands
|
||||
TCommands* = enum # Nim's commands
|
||||
# **keep binary compatible**
|
||||
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
|
||||
|
|
@ -114,7 +114,8 @@ var
|
|||
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
|
||||
# the tracked source X, saved by the CAAS client.
|
||||
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
|
||||
gNoBabelPath* = false
|
||||
gNoNimblePath* = false
|
||||
gExperimentalMode*: bool
|
||||
|
||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
||||
|
|
@ -139,7 +140,7 @@ const
|
|||
JsonExt* = "json"
|
||||
TexExt* = "tex"
|
||||
IniExt* = "ini"
|
||||
DefaultConfig* = "nimrod.cfg"
|
||||
DefaultConfig* = "nim.cfg"
|
||||
DocConfig* = "nimdoc.cfg"
|
||||
DocTexConfig* = "nimdoc.tex.cfg"
|
||||
|
||||
|
|
@ -152,7 +153,6 @@ var
|
|||
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
||||
gProjectFull* = "" # projectPath/projectName
|
||||
gProjectMainIdx*: int32 # the canonical path id of the main module
|
||||
optMainModule* = "" # the main module that should be used for idetools commands
|
||||
nimcacheDir* = ""
|
||||
command* = "" # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs*: seq[string] = @[] # any arguments after the main command
|
||||
|
|
@ -189,8 +189,8 @@ proc getPrefixDir*(): string =
|
|||
result = splitPath(getAppDir()).head
|
||||
|
||||
proc canonicalizePath*(path: string): string =
|
||||
result = path.expandFilename
|
||||
when not FileSystemCaseSensitive: result = result.toLower
|
||||
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
|
||||
else: result = path.expandFilename
|
||||
|
||||
proc shortenDir*(dir: string): string =
|
||||
## returns the interesting part of a dir
|
||||
|
|
@ -238,6 +238,9 @@ proc getPackageName*(path: string): string =
|
|||
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
|
||||
return packageCache[d]
|
||||
inc parents
|
||||
for file in walkFiles(d / "*.nimble"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
for file in walkFiles(d / "*.babel"):
|
||||
result = file.splitFile.name
|
||||
break packageSearch
|
||||
|
|
@ -295,7 +298,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
|||
createDir(subdir)
|
||||
when noTimeMachine:
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
except EOS:
|
||||
except OSError:
|
||||
writeln(stdout, "cannot create directory: " & subdir)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
|
|
@ -335,6 +338,16 @@ proc findFile*(f: string): string {.procvar.} =
|
|||
|
||||
proc findModule*(modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
when defined(nimfix):
|
||||
# '.nimfix' modules are preferred over '.nim' modules so that specialized
|
||||
# versions can be kept for 'nimfix'.
|
||||
block:
|
||||
let m = addFileExt(modulename, "nimfix")
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = findFile(m)
|
||||
if existsFile(result): return result
|
||||
let m = addFileExt(modulename, NimExt)
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements the parser of the standard Nimrod syntax.
|
||||
# This module implements the parser of the standard Nim syntax.
|
||||
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
||||
# it uses several helper routines to keep the parser small. A special
|
||||
# efficient algorithm is used for the precedence levels. The parser here can
|
||||
|
|
@ -41,8 +41,7 @@ type
|
|||
proc parseAll*(p: var TParser): PNode
|
||||
proc closeParser*(p: var TParser)
|
||||
proc parseTopLevelStmt*(p: var TParser): PNode
|
||||
proc parseString*(s: string, filename: string = "", line: int = 0): PNode
|
||||
|
||||
|
||||
# helpers for the other parsers
|
||||
proc isOperator*(tok: TToken): bool
|
||||
proc getTok*(p: var TParser)
|
||||
|
|
@ -84,7 +83,7 @@ proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
|
|||
|
||||
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||
strongSpaces=false) =
|
||||
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
|
||||
openParser(p, filename.fileInfoIdx, inputStream, strongSpaces)
|
||||
|
||||
proc closeParser(p: var TParser) =
|
||||
## Close a parser, freeing up its resources.
|
||||
|
|
@ -96,7 +95,7 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
|||
|
||||
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
|
||||
## Produce and emit a parser message to output about the token `tok`
|
||||
lexMessage(p.lex, msg, prettyTok(tok))
|
||||
parMessage(p, msg, prettyTok(tok))
|
||||
|
||||
template withInd(p: expr, body: stmt) {.immediate.} =
|
||||
let oldInd = p.currInd
|
||||
|
|
@ -189,18 +188,13 @@ proc parseTypeDesc(p: var TParser): PNode
|
|||
proc parseDoBlocks(p: var TParser, call: PNode)
|
||||
proc parseParamList(p: var TParser, retColon = true): PNode
|
||||
|
||||
proc relevantOprChar(ident: PIdent): char {.inline.} =
|
||||
result = ident.s[0]
|
||||
var L = ident.s.len
|
||||
if result == '\\' and L > 1:
|
||||
result = ident.s[1]
|
||||
|
||||
proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
|
||||
result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
|
||||
|
||||
proc isLeftAssociative(tok: TToken): bool {.inline.} =
|
||||
## Determines whether the token is left assocative.
|
||||
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
|
||||
proc isRightAssociative(tok: TToken): bool {.inline.} =
|
||||
## Determines whether the token is right assocative.
|
||||
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
|
||||
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
||||
|
||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
## Calculates the precedence of the given token.
|
||||
|
|
@ -210,7 +204,10 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
|||
case tok.tokType
|
||||
of tkOpr:
|
||||
let L = tok.ident.s.len
|
||||
let relevantChar = relevantOprChar(tok.ident)
|
||||
let relevantChar = tok.ident.s[0]
|
||||
|
||||
# arrow like?
|
||||
if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
|
||||
|
||||
template considerAsgn(value: expr) =
|
||||
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
|
||||
|
|
@ -270,17 +267,18 @@ proc checkBinary(p: TParser) {.inline.} =
|
|||
#|
|
||||
#| optInd = COMMENT?
|
||||
#| optPar = (IND{>} | IND{=})?
|
||||
#|
|
||||
#| simpleExpr = assignExpr (OP0 optInd assignExpr)*
|
||||
#| assignExpr = orExpr (OP1 optInd orExpr)*
|
||||
#| orExpr = andExpr (OP2 optInd andExpr)*
|
||||
#| andExpr = cmpExpr (OP3 optInd cmpExpr)*
|
||||
#| cmpExpr = sliceExpr (OP4 optInd sliceExpr)*
|
||||
#| sliceExpr = ampExpr (OP5 optInd ampExpr)*
|
||||
#| ampExpr = plusExpr (OP6 optInd plusExpr)*
|
||||
#| plusExpr = mulExpr (OP7 optInd mulExpr)*
|
||||
#| mulExpr = dollarExpr (OP8 optInd dollarExpr)*
|
||||
#| dollarExpr = primary (OP9 optInd primary)*
|
||||
#|
|
||||
#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
|
||||
#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
|
||||
#| assignExpr = orExpr (OP2 optInd orExpr)*
|
||||
#| orExpr = andExpr (OP3 optInd andExpr)*
|
||||
#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
|
||||
#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
|
||||
#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
|
||||
#| ampExpr = plusExpr (OP7 optInd plusExpr)*
|
||||
#| plusExpr = mulExpr (OP8 optInd mulExpr)*
|
||||
#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
|
||||
#| dollarExpr = primary (OP10 optInd primary)*
|
||||
|
||||
proc colcom(p: var TParser, n: PNode) =
|
||||
eat(p, tkColon)
|
||||
|
|
@ -507,7 +505,7 @@ proc parsePar(p: var TParser): PNode =
|
|||
getTok(p)
|
||||
optInd(p, result)
|
||||
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
||||
tkTry, tkFinally, tkExcept, tkFor, tkBlock,
|
||||
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
|
||||
tkConst, tkLet, tkWhen, tkVar,
|
||||
tkMixin}:
|
||||
# XXX 'bind' used to be an expression, so we exclude it here;
|
||||
|
|
@ -735,7 +733,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
|
|||
# the operator itself must not start on a new line:
|
||||
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
|
||||
checkBinary(p)
|
||||
var leftAssoc = ord(isLeftAssociative(p.tok))
|
||||
var leftAssoc = 1-ord(isRightAssociative(p.tok))
|
||||
var a = newNodeP(nkInfix, p)
|
||||
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
||||
getTok(p)
|
||||
|
|
@ -896,7 +894,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
|||
var a: PNode
|
||||
result = newNodeP(nkFormalParams, p)
|
||||
addSon(result, ast.emptyNode) # return type
|
||||
if p.tok.tokType == tkParLe and p.tok.indent < 0:
|
||||
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
|
||||
if hasParLe:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while true:
|
||||
|
|
@ -920,6 +919,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
|||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.sons[0] = parseTypeDesc(p)
|
||||
elif not retColon and not hasParle:
|
||||
# Mark as "not there" in order to mark for deprecation in the semantic pass:
|
||||
result = ast.emptyNode
|
||||
|
||||
proc optPragmas(p: var TParser): PNode =
|
||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
|
||||
|
|
@ -1132,7 +1134,7 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
|||
skipComment(p, result)
|
||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
addSon(result, newProcNode(nkDo, body.info, body))
|
||||
addSon(result, makeStmtList(body))
|
||||
while sameInd(p):
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
|
|
@ -1424,9 +1426,10 @@ proc parseBlock(p: var TParser): PNode =
|
|||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
||||
proc parseStatic(p: var TParser): PNode =
|
||||
proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
|
||||
#| staticStmt = 'static' colcom stmt
|
||||
result = newNodeP(nkStaticStmt, p)
|
||||
#| deferStmt = 'defer' colcom stmt
|
||||
result = newNodeP(k, p)
|
||||
getTokNoInd(p)
|
||||
colcom(p, result)
|
||||
addSon(result, parseStmt(p))
|
||||
|
|
@ -1864,7 +1867,7 @@ proc simpleStmt(p: var TParser): PNode =
|
|||
proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||
#| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
|
||||
#| | tryStmt | finallyStmt | exceptStmt | forStmt
|
||||
#| | blockStmt | staticStmt | asmStmt
|
||||
#| | blockStmt | staticStmt | deferStmt | asmStmt
|
||||
#| | 'proc' routine
|
||||
#| | 'method' routine
|
||||
#| | 'iterator' routine
|
||||
|
|
@ -1885,7 +1888,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
|||
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
||||
of tkFor: result = parseFor(p)
|
||||
of tkBlock: result = parseBlock(p)
|
||||
of tkStatic: result = parseStatic(p)
|
||||
of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
|
||||
of tkDefer: result = parseStaticOrDefer(p, nkDefer)
|
||||
of tkAsm: result = parseAsm(p)
|
||||
of tkProc: result = parseRoutine(p, nkProcDef)
|
||||
of tkMethod: result = parseRoutine(p, nkMethodDef)
|
||||
|
|
@ -1980,22 +1984,25 @@ proc parseTopLevelStmt(p: var TParser): PNode =
|
|||
## top-level statement or emptyNode if end of stream.
|
||||
result = ast.emptyNode
|
||||
while true:
|
||||
if p.tok.indent != 0:
|
||||
if p.tok.indent != 0:
|
||||
if p.firstTok and p.tok.indent < 0: discard
|
||||
else: parMessage(p, errInvalidIndentation)
|
||||
elif p.tok.tokType != tkSemiColon:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
p.firstTok = false
|
||||
case p.tok.tokType
|
||||
of tkSemiColon:
|
||||
getTok(p)
|
||||
if p.tok.indent <= 0: discard
|
||||
else: parMessage(p, errInvalidIndentation)
|
||||
p.firstTok = true
|
||||
of tkEof: break
|
||||
else:
|
||||
result = complexOrSimpleStmt(p)
|
||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||
break
|
||||
|
||||
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
|
||||
proc parseString*(s: string; filename: string = ""; line: int = 0;
|
||||
errorHandler: TErrorHandler = nil): PNode =
|
||||
## Parses a string into an AST, returning the top node.
|
||||
## `filename` and `line`, although optional, provide info so that the
|
||||
## compiler can generate correct error messages referring to the original
|
||||
|
|
@ -2007,6 +2014,7 @@ proc parseString(s: string, filename: string = "", line: int = 0): PNode =
|
|||
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
||||
# spaces...
|
||||
openParser(parser, filename, stream, false)
|
||||
parser.lex.errorHandler = errorHandler
|
||||
|
||||
result = parser.parseAll
|
||||
closeParser(parser)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -16,7 +16,7 @@ import
|
|||
nimsets, syntaxes, times, rodread, idgen
|
||||
|
||||
type
|
||||
TPassContext* = object of TObject # the pass's context
|
||||
TPassContext* = object of RootObj # the pass's context
|
||||
fromCache*: bool # true if created by "openCached"
|
||||
|
||||
PPassContext* = ref TPassContext
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -260,7 +260,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
|||
# couldn't bind parameter:
|
||||
if isNil(x): return nil
|
||||
result.add(x)
|
||||
if requiresAA: addToArgList(args, n)
|
||||
if requiresAA: addToArgList(args, x)
|
||||
# perform alias analysis here:
|
||||
if requiresAA:
|
||||
for i in 1 .. < params.len:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const
|
|||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||
wInjectStmt, wDeprecated}
|
||||
wInjectStmt, wDeprecated, wExperimental}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||
|
|
@ -71,7 +71,7 @@ const
|
|||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||
# implementation
|
||||
|
||||
proc invalidPragma(n: PNode) =
|
||||
proc invalidPragma(n: PNode) =
|
||||
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
|
|
@ -130,6 +130,7 @@ proc processImportCpp(s: PSym, extname: string) =
|
|||
excl(s.flags, sfForward)
|
||||
let m = s.getModule()
|
||||
incl(m.flags, sfCompileToCpp)
|
||||
extccomp.gMixedMode = true
|
||||
|
||||
proc processImportObjC(s: PSym, extname: string) =
|
||||
setExternName(s, extname)
|
||||
|
|
@ -356,11 +357,11 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
|||
append(c.optionStack, x)
|
||||
for i in countup(start, sonsLen(n) - 1):
|
||||
if processOption(c, n.sons[i]):
|
||||
# simply store it somehwere:
|
||||
# simply store it somewhere:
|
||||
if x.otherPragmas.isNil:
|
||||
x.otherPragmas = newNodeI(nkPragma, n.info)
|
||||
x.otherPragmas.add n.sons[i]
|
||||
#LocalError(n.info, errOptionExpected)
|
||||
#localError(n.info, errOptionExpected)
|
||||
|
||||
proc processPop(c: PContext, n: PNode) =
|
||||
if c.optionStack.counter <= 1:
|
||||
|
|
@ -447,6 +448,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
|||
addSon(result, newSymNode(e))
|
||||
else:
|
||||
addSon(result, newStrNode(nkStrLit, sub))
|
||||
else:
|
||||
# an empty '``' produces a single '`'
|
||||
addSon(result, newStrNode(nkStrLit, $marker))
|
||||
if c < 0: break
|
||||
a = c + 1
|
||||
else: illFormedAst(n)
|
||||
|
|
@ -518,6 +522,28 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
|||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc pragmaLockStmt(c: PContext; it: PNode) =
|
||||
if it.kind != nkExprColonExpr:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
let n = it[1]
|
||||
if n.kind != nkBracket:
|
||||
localError(n.info, errGenerated, "locks pragma takes a list of expressions")
|
||||
else:
|
||||
for i in 0 .. <n.len:
|
||||
n.sons[i] = c.semExpr(c, n.sons[i])
|
||||
|
||||
proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
|
||||
if it.kind != nkExprColonExpr:
|
||||
invalidPragma(it)
|
||||
else:
|
||||
if it[1].kind != nkNilLit:
|
||||
let x = expectIntLit(c, it)
|
||||
if x < 0 or x > MaxLockLevel:
|
||||
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
|
||||
else:
|
||||
result = TLockLevel(x)
|
||||
|
||||
proc typeBorrow(sym: PSym, n: PNode) =
|
||||
if n.kind == nkExprColonExpr:
|
||||
let it = n.sons[1]
|
||||
|
|
@ -575,6 +601,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
if c.instCounter > 100:
|
||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||
pragma(c, sym, userPragma.ast, validPragmas)
|
||||
# ensure the pragma is also remember for generic instantiations in other
|
||||
# modules:
|
||||
n.sons[i] = userPragma.ast
|
||||
dec c.instCounter
|
||||
else:
|
||||
var k = whichKeyword(key.ident)
|
||||
|
|
@ -807,6 +836,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
if sym == nil: invalidPragma(it)
|
||||
of wLine: pragmaLine(c, it)
|
||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||
of wLocks:
|
||||
if sym == nil: pragmaLockStmt(c, it)
|
||||
elif sym.typ == nil: invalidPragma(it)
|
||||
else: sym.typ.lockLevel = pragmaLocks(c, it)
|
||||
of wGuard:
|
||||
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||
invalidPragma(it)
|
||||
|
|
@ -817,6 +850,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
localError(it.info, errExprExpected)
|
||||
else:
|
||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||
of wExperimental:
|
||||
noVal(it)
|
||||
if isTopLevel(c):
|
||||
c.module.flags.incl sfExperimental
|
||||
else:
|
||||
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
|
|
@ -853,8 +892,13 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
|||
|
||||
return false
|
||||
|
||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
if n == nil: return
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if singlePragma(c, sym, n, i, validPragmas): break
|
||||
if n.sons[i].kind == nkPragma: pragmaRec(c, sym, n.sons[i], validPragmas)
|
||||
elif singlePragma(c, sym, n, i, validPragmas): break
|
||||
|
||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
if n == nil: return
|
||||
pragmaRec(c, sym, n, validPragmas)
|
||||
implicitPragmas(c, sym, n, validPragmas)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
# This is needed for proper handling of forward declarations.
|
||||
|
||||
import
|
||||
ast, astalgo, msgs, semdata, types, trees
|
||||
ast, astalgo, msgs, semdata, types, trees, strutils
|
||||
|
||||
proc equalGenericParams(procA, procB: PNode): bool =
|
||||
if sonsLen(procA) != sonsLen(procB): return
|
||||
|
|
@ -68,11 +68,17 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
|||
ExactConstraints, IgnoreCC}
|
||||
|
||||
var it: TIdentIter
|
||||
|
||||
result = initIdentIter(it, scope.symbols, fn.name)
|
||||
while result != nil:
|
||||
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
||||
case equalParams(result.typ.n, fn.typ.n)
|
||||
of paramsEqual:
|
||||
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
||||
let message = ("public implementation '$1' has non-public " &
|
||||
"forward declaration in $2") %
|
||||
[getProcHeader(result), $result.info]
|
||||
localError(fn.info, errGenerated, message)
|
||||
return
|
||||
of paramsIncompatible:
|
||||
localError(fn.info, errNotOverloadable, fn.name.s)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
This directory contains the Nimrod compiler written in Nimrod. Note that this
|
||||
This directory contains the Nim compiler written in Nim. Note that this
|
||||
code has been translated from a bootstrapping version written in Pascal, so
|
||||
the code is **not** a poster child of good Nimrod code.
|
||||
the code is **not** a poster child of good Nim code.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# This module implements the renderer of the standard Nimrod representation.
|
||||
# This module implements the renderer of the standard Nim representation.
|
||||
|
||||
import
|
||||
lexer, options, idents, strutils, ast, msgs, lists
|
||||
|
|
@ -34,6 +34,7 @@ type
|
|||
comStack*: seq[PNode] # comment stack
|
||||
flags*: TRenderFlags
|
||||
checkAnon: bool # we're in a context that can contain sfAnon
|
||||
inPragma: int
|
||||
|
||||
|
||||
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
|
||||
|
|
@ -620,7 +621,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
|
|||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
||||
incl(c.flags, rfLongMode)
|
||||
gcoms(g) # a good place for comments
|
||||
gstmts(g, n.sons[0], c)
|
||||
gstmts(g, n, c)
|
||||
put(g, tkCurlyRi, "}")
|
||||
|
||||
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
||||
|
|
@ -894,8 +895,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
put(g, tkParLe, "(")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if i > 0: put(g, tkOpr, "|")
|
||||
gsub(g, n.sons[i], c)
|
||||
put(g, tkParRi, ")")
|
||||
if n.sons[i].kind == nkSym:
|
||||
let s = n[i].sym
|
||||
if s.owner != nil:
|
||||
put g, tkSymbol, n[i].sym.owner.name.s
|
||||
put g, tkOpr, "."
|
||||
put g, tkSymbol, n[i].sym.name.s
|
||||
else:
|
||||
gsub(g, n.sons[i], c)
|
||||
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
|
||||
of nkPar, nkClosure:
|
||||
put(g, tkParLe, "(")
|
||||
gcomma(g, n, c)
|
||||
|
|
@ -940,10 +948,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
of nkConstDef, nkIdentDefs:
|
||||
gcomma(g, n, 0, -3)
|
||||
var L = sonsLen(n)
|
||||
if n.sons[L - 2].kind != nkEmpty:
|
||||
if L >= 2 and n.sons[L - 2].kind != nkEmpty:
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n.sons[L - 2])
|
||||
if n.sons[L - 1].kind != nkEmpty:
|
||||
if L >= 1 and n.sons[L - 1].kind != nkEmpty:
|
||||
put(g, tkSpaces, Space)
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
gsub(g, n.sons[L - 1], c)
|
||||
|
|
@ -1009,9 +1017,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
put(g, tkElse, " else")
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n.sons[0])
|
||||
of nkTypeOfExpr:
|
||||
of nkTypeOfExpr:
|
||||
putWithSpace(g, tkType, "type")
|
||||
gsub(g, n.sons[0])
|
||||
if n.len > 0: gsub(g, n.sons[0])
|
||||
of nkRefTy:
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkRef, "ref")
|
||||
|
|
@ -1177,12 +1185,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
of nkContinueStmt:
|
||||
putWithSpace(g, tkContinue, "continue")
|
||||
gsub(g, n.sons[0])
|
||||
of nkPragma:
|
||||
of nkPragma:
|
||||
if renderNoPragmas notin g.flags:
|
||||
put(g, tkSpaces, Space)
|
||||
put(g, tkCurlyDotLe, "{.")
|
||||
gcomma(g, n, emptyContext)
|
||||
put(g, tkCurlyDotRi, ".}")
|
||||
if g.inPragma <= 0:
|
||||
inc g.inPragma
|
||||
put(g, tkSpaces, Space)
|
||||
put(g, tkCurlyDotLe, "{.")
|
||||
gcomma(g, n, emptyContext)
|
||||
put(g, tkCurlyDotRi, ".}")
|
||||
dec g.inPragma
|
||||
else:
|
||||
gcomma(g, n, emptyContext)
|
||||
of nkImportStmt, nkExportStmt:
|
||||
if n.kind == nkImportStmt:
|
||||
putWithSpace(g, tkImport, "import")
|
||||
|
|
@ -1306,7 +1319,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
|
|||
proc renderModule(n: PNode, filename: string,
|
||||
renderFlags: TRenderFlags = {}) =
|
||||
var
|
||||
f: TFile
|
||||
f: File
|
||||
g: TSrcGen
|
||||
initSrcGen(g, renderFlags)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -121,7 +121,7 @@ type
|
|||
r*: string # writers use this
|
||||
offset*: int # readers use this
|
||||
|
||||
TRodReader* = object of TObject
|
||||
TRodReader* = object of RootObj
|
||||
pos: int # position; used for parsing
|
||||
s: cstring # mmap'ed file contents
|
||||
options: TOptions
|
||||
|
|
@ -137,7 +137,7 @@ type
|
|||
line: int # only used for debugging, but is always in the code
|
||||
moduleID: int
|
||||
syms: TIdTable # already processed symbols
|
||||
memfile: TMemFile # unfortunately there is no point in time where we
|
||||
memfile: MemFile # unfortunately there is no point in time where we
|
||||
# can close this! XXX
|
||||
methods*: TSymSeq
|
||||
origFile: string
|
||||
|
|
@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
|
|||
loc.r = toRope(decodeStr(r.s, r.pos))
|
||||
else:
|
||||
loc.r = nil
|
||||
if r.s[r.pos] == '?':
|
||||
inc(r.pos)
|
||||
loc.a = decodeVInt(r.s, r.pos)
|
||||
else:
|
||||
loc.a = 0
|
||||
if r.s[r.pos] == '>': inc(r.pos)
|
||||
else: internalError(info, "decodeLoc " & r.s[r.pos])
|
||||
|
||||
|
|
@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
|||
result.size = - 1
|
||||
if r.s[r.pos] == '=':
|
||||
inc(r.pos)
|
||||
result.align = decodeVInt(r.s, r.pos)
|
||||
result.align = decodeVInt(r.s, r.pos).int16
|
||||
else:
|
||||
result.align = 2
|
||||
decodeLoc(r, result.loc, info)
|
||||
|
|
@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
|
|||
idTablePut(r.syms, s, s)
|
||||
strTableAdd(rodCompilerprocs, s)
|
||||
|
||||
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
|
||||
proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) =
|
||||
var key, val, tmp: int
|
||||
inc(r.pos, 2) # skip "(\10"
|
||||
inc(r.line)
|
||||
|
|
@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
|||
new(result)
|
||||
try:
|
||||
result.memfile = memfiles.open(modfilename)
|
||||
except EOS:
|
||||
except OSError:
|
||||
return nil
|
||||
result.files = @[]
|
||||
result.modDeps = @[]
|
||||
|
|
@ -916,7 +911,7 @@ initIdTable(gTypeTable)
|
|||
initStrTable(rodCompilerprocs)
|
||||
|
||||
# viewer:
|
||||
proc writeNode(f: TFile; n: PNode) =
|
||||
proc writeNode(f: File; n: PNode) =
|
||||
f.write("(")
|
||||
if n != nil:
|
||||
f.write($n.kind)
|
||||
|
|
@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) =
|
|||
writeNode(f, n.sons[i])
|
||||
f.write(")")
|
||||
|
||||
proc writeSym(f: TFile; s: PSym) =
|
||||
proc writeSym(f: File; s: PSym) =
|
||||
if s == nil:
|
||||
f.write("{}\n")
|
||||
return
|
||||
|
|
@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) =
|
|||
f.writeNode(s.ast)
|
||||
f.write("}\n")
|
||||
|
||||
proc writeType(f: TFile; t: PType) =
|
||||
proc writeType(f: File; t: PType) =
|
||||
if t == nil:
|
||||
f.write("[]\n")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -187,9 +187,6 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
|||
if loc.r != nil:
|
||||
add(result, '!')
|
||||
encodeStr(ropeToStr(loc.r), result)
|
||||
if loc.a != 0:
|
||||
add(result, '?')
|
||||
encodeVInt(loc.a, result)
|
||||
if oldLen + 1 == result.len:
|
||||
# no data was necessary, so remove the '<' again:
|
||||
setLen(result, oldLen)
|
||||
|
|
@ -297,7 +294,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
|||
# the last entry of a symbol:
|
||||
if s.ast != nil:
|
||||
# we used to attempt to save space here by only storing a dummy AST if
|
||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
||||
# it is not necessary, but Nim's heavy compile-time evaluation features
|
||||
# make that unfeasible nowadays:
|
||||
encodeNode(w, s.info, s.ast, result)
|
||||
when false:
|
||||
|
|
@ -422,7 +419,7 @@ proc addStmt(w: PRodWriter, n: PNode) =
|
|||
|
||||
proc writeRod(w: PRodWriter) =
|
||||
processStacks(w, true)
|
||||
var f: TFile
|
||||
var f: File
|
||||
if not open(f, completeGeneratedFilePath(changeFileExt(
|
||||
w.filename.withPackageName, RodExt)),
|
||||
fmWrite):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
# Ropes are a data structure that represents a very long string
|
||||
# efficiently; especially concatenation is done in O(1) instead of O(N).
|
||||
# Ropes make use a lazy evaluation: They are essentially concatenation
|
||||
# trees that are only flattened when converting to a native Nimrod
|
||||
# trees that are only flattened when converting to a native Nim
|
||||
# string or when written to disk. The empty string is represented by a
|
||||
# nil pointer.
|
||||
# A little picture makes everything clear:
|
||||
|
|
@ -64,7 +64,7 @@ type
|
|||
# copy the format strings
|
||||
# though it is not necessary)
|
||||
PRope* = ref TRope
|
||||
TRope*{.acyclic.} = object of TObject # the empty rope is represented
|
||||
TRope*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||
# by nil to safe space
|
||||
left*, right*: PRope
|
||||
length*: int
|
||||
|
|
@ -216,7 +216,7 @@ proc app(a: var PRope, b: PRope) = a = con(a, b)
|
|||
proc app(a: var PRope, b: string) = a = con(a, b)
|
||||
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
|
||||
|
||||
proc writeRope*(f: TFile, c: PRope) =
|
||||
proc writeRope*(f: File, c: PRope) =
|
||||
var stack = @[c]
|
||||
while len(stack) > 0:
|
||||
var it = pop(stack)
|
||||
|
|
@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) =
|
|||
write(f, it.data)
|
||||
|
||||
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
||||
var f: TFile
|
||||
var f: File
|
||||
if open(f, filename, fmWrite):
|
||||
if head != nil: writeRope(f, head)
|
||||
close(f)
|
||||
|
|
@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
|||
const
|
||||
bufSize = 1024 # 1 KB is reasonable
|
||||
|
||||
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
|
||||
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
|
||||
if r.data != nil:
|
||||
if r.length > bufSize:
|
||||
errorHandler(rTokenTooLong, r.data)
|
||||
|
|
@ -312,7 +312,7 @@ proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
|
|||
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
||||
|
||||
proc ropeEqualsFile(r: PRope, f: string): bool =
|
||||
var bin: TFile
|
||||
var bin: File
|
||||
result = open(bin, f)
|
||||
if not result:
|
||||
return # not equal if file does not exist
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -15,9 +15,12 @@ import
|
|||
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
|
||||
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
|
||||
semparallel, lowerings
|
||||
|
||||
when defined(nimfix):
|
||||
import nimfix.prettybase
|
||||
|
||||
# implementation
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
|
||||
|
|
@ -37,9 +40,7 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
|||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
proc finishMethod(c: PContext, s: PSym)
|
||||
|
|
@ -66,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
|||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
else:
|
||||
let x = result.skipConv
|
||||
if x.kind == nkPar and formal.kind != tyExpr:
|
||||
changeType(x, formal, check=true)
|
||||
|
||||
proc inferWithMetatype(c: PContext, formal: PType,
|
||||
arg: PNode, coerceDistincts = false): PNode
|
||||
|
||||
var commonTypeBegin = PType(kind: tyExpr)
|
||||
|
||||
proc isEmptyContainer(t: PType): bool =
|
||||
case t.kind
|
||||
of tyExpr, tyNil: result = true
|
||||
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
|
||||
of tySet, tySequence, tyOpenArray, tyVarargs:
|
||||
result = t.sons[0].kind == tyEmpty
|
||||
of tyGenericInst: result = isEmptyContainer(t.lastSon)
|
||||
else: result = false
|
||||
|
||||
proc commonType*(x, y: PType): PType =
|
||||
# new type relation that is used for array constructors,
|
||||
# if expressions, etc.:
|
||||
|
|
@ -95,6 +109,13 @@ proc commonType*(x, y: PType): PType =
|
|||
# check for seq[empty] vs. seq[int]
|
||||
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
||||
if a.sons[idx].kind == tyEmpty: return y
|
||||
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
|
||||
var nt: PType
|
||||
for i in 0.. <a.len:
|
||||
if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
|
||||
if nt.isNil: nt = copyType(a, a.owner, false)
|
||||
nt.sons[i] = b.sons[i]
|
||||
if not nt.isNil: result = nt
|
||||
#elif b.sons[idx].kind == tyEmpty: return x
|
||||
elif a.kind == tyRange and b.kind == tyRange:
|
||||
# consider: (range[0..3], range[0..4]) here. We should make that
|
||||
|
|
@ -131,17 +152,14 @@ proc commonType*(x, y: PType): PType =
|
|||
result = newType(k, r.owner)
|
||||
result.addSonSkipIntLit(r)
|
||||
|
||||
proc isTopLevel(c: PContext): bool {.inline.} =
|
||||
result = c.currentScope.depthLevel <= 2
|
||||
|
||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
||||
|
||||
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
# like newSymS, but considers gensym'ed symbols
|
||||
if n.kind == nkSym:
|
||||
# and sfGenSym in n.sym.flags:
|
||||
result = n.sym
|
||||
internalAssert sfGenSym in result.flags
|
||||
internalAssert result.kind == kind
|
||||
# when there is a nested proc inside a template, semtmpl
|
||||
# will assign a wrong owner during the first pass over the
|
||||
|
|
@ -308,6 +326,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
|||
pushInfoContext(nOrig.info)
|
||||
|
||||
markUsed(n.info, sym)
|
||||
styleCheckUse(n.info, sym)
|
||||
if sym == c.p.owner:
|
||||
globalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||
|
||||
|
|
@ -340,7 +359,7 @@ type
|
|||
TSemGenericFlags = set[TSemGenericFlag]
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode
|
||||
ctx: var IntSet): PNode
|
||||
|
||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||
|
||||
|
|
@ -367,6 +386,8 @@ proc myOpen(module: PSym): PPassContext =
|
|||
c.semInferredLambda = semInferredLambda
|
||||
c.semGenerateInstance = generateInstance
|
||||
c.semTypeNode = semTypeNode
|
||||
c.instDeepCopy = sigmatch.instDeepCopy
|
||||
|
||||
pushProcCon(c, module)
|
||||
pushOwner(c.module)
|
||||
c.importTable = openScope(c)
|
||||
|
|
|
|||
197
compiler/semasgn.nim
Normal file
197
compiler/semasgn.nim
Normal 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)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
errors: var seq[string]) =
|
||||
errors: var CandidateErrors) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
|
|
@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
z.calleeSym = sym
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(getProcHeader(sym))
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors[errors.len - 1].add("\n " & err)
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
|
|
@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
else: discard
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
|
|
@ -83,18 +83,38 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
|||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1))
|
||||
add(result, ')')
|
||||
|
||||
# to avoid confusing errors like:
|
||||
# got (SslPtr, SocketHandle)
|
||||
# but expected one of:
|
||||
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
||||
# we do a pre-analysis. If all types produce the same string, we will add
|
||||
# module information.
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
|
||||
var prefer = preferName
|
||||
for err in errors:
|
||||
var errProto = ""
|
||||
let n = err.typ.n
|
||||
for i in countup(1, n.len - 1):
|
||||
var p = n.sons[i]
|
||||
if p.kind == nkSym:
|
||||
add(errProto, typeToString(p.sym.typ, preferName))
|
||||
if i != n.len-1: add(errProto, ", ")
|
||||
# else: ignore internal error as we're already in error handling mode
|
||||
if errProto == proto:
|
||||
prefer = preferModuleInfo
|
||||
break
|
||||
# now use the information stored in 'prefer' to produce a nice error message:
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1, prefer))
|
||||
add(result, ')')
|
||||
var candidates = ""
|
||||
for err in errors:
|
||||
add(candidates, err)
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||
|
|
@ -114,7 +134,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
else:
|
||||
initialBinding = nil
|
||||
|
||||
var errors: seq[string]
|
||||
var errors: CandidateErrors
|
||||
var usedSyms: seq[PNode]
|
||||
|
||||
template pickBest(headSymbol: expr) =
|
||||
|
|
@ -254,6 +274,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
|||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
markUsed(n.sons[0].info, finalCallee)
|
||||
styleCheckUse(n.sons[0].info, finalCallee)
|
||||
if finalCallee.ast == nil:
|
||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||
|
|
@ -286,6 +307,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
|||
initCandidate(c, m, s, n)
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
|
|
@ -305,7 +327,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
|||
result = explicitGenericSym(c, n, s)
|
||||
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
||||
# choose the generic proc with the proper number of type parameters.
|
||||
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
|
||||
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
|
||||
# It's good enough for now.
|
||||
result = newNodeI(a.kind, n.info)
|
||||
for i in countup(0, len(a)-1):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -57,7 +57,7 @@ type
|
|||
# can access private object fields
|
||||
instCounter*: int # to prevent endless instantiations
|
||||
|
||||
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||
# store this info in the syms themselves!)
|
||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
||||
inGenericContext*: int # > 0 if we are in a generic type
|
||||
|
|
@ -72,8 +72,7 @@ type
|
|||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
||||
bufferErrors = false): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
|
|
@ -83,15 +82,18 @@ type
|
|||
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
|
||||
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym
|
||||
includedFiles*: TIntSet # used to detect recursive include files
|
||||
includedFiles*: IntSet # used to detect recursive include files
|
||||
userPragmas*: TStrTable
|
||||
evalContext*: PEvalContext
|
||||
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
|
||||
# naming it multiple times
|
||||
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||
inParallelStmt*: int
|
||||
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||
info: TLineInfo): PSym {.nimcall.}
|
||||
|
||||
|
||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||
result.genericSym = s
|
||||
|
|
@ -310,3 +312,8 @@ proc checkSonsLen*(n: PNode, length: int) =
|
|||
proc checkMinSonsLen*(n: PNode, length: int) =
|
||||
if sonsLen(n) < length: illFormedAst(n)
|
||||
|
||||
proc isTopLevel*(c: PContext): bool {.inline.} =
|
||||
result = c.currentScope.depthLevel <= 2
|
||||
|
||||
proc experimentalMode*(c: PContext): bool {.inline.} =
|
||||
result = gExperimentalMode or sfExperimental in c.module.flags
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
pushInfoContext(n.info)
|
||||
result = evalTemplate(n, s, getCurrOwner())
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
||||
|
|
@ -79,6 +80,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
case s.kind
|
||||
of skConst:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyTuple, tySet, tyUInt..tyUInt64:
|
||||
|
|
@ -103,6 +105,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||
of skVar, skLet, skResult, skParam, skForVar:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
if sfGlobal in s.flags:
|
||||
incl(c.p.owner.flags, sfSideEffect)
|
||||
|
|
@ -115,6 +118,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
# var len = 0 # but won't be called
|
||||
# genericThatUsesLen(x) # marked as taking a closure?
|
||||
of skGenericParam:
|
||||
styleCheckUse(n.info, s)
|
||||
if s.typ.kind == tyStatic:
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = s.typ
|
||||
|
|
@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
return n
|
||||
of skType:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||
return s.typ.n
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = makeTypeDesc(c, s.typ)
|
||||
else:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
type
|
||||
|
|
@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
|||
let status = checkConvertible(c, result.typ, it.typ)
|
||||
if status in {convOK, convNotNeedeed}:
|
||||
markUsed(n.info, it.sym)
|
||||
styleCheckUse(n.info, it.sym)
|
||||
markIndirect(c, it.sym)
|
||||
return it
|
||||
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
|
||||
|
|
@ -360,6 +367,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
|||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator notin t.flags))
|
||||
else: discard
|
||||
else:
|
||||
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
||||
maybeLiftType(t2, c, n.info)
|
||||
|
|
@ -415,34 +423,22 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
|||
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||
result = semExpr(c, result)
|
||||
|
||||
proc changeType(n: PNode, newType: PType, check: bool) =
|
||||
proc changeType(n: PNode, newType: PType, check: bool) =
|
||||
case n.kind
|
||||
of nkCurly, nkBracket:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
of nkCurly, nkBracket:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
changeType(n.sons[i], elemType(newType), check)
|
||||
of nkPar:
|
||||
if newType.kind != tyTuple:
|
||||
of nkPar:
|
||||
let tup = newType.skipTypes({tyGenericInst})
|
||||
if tup.kind != tyTuple:
|
||||
internalError(n.info, "changeType: no tuple type for constructor")
|
||||
elif newType.n == nil: discard
|
||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = n.sons[i].sons[0]
|
||||
if m.kind != nkSym:
|
||||
internalError(m.info, "changeType(): invalid tuple constr")
|
||||
return
|
||||
var f = getSymFromList(newType.n, m.sym.name)
|
||||
if f == nil:
|
||||
internalError(m.info, "changeType(): invalid identifier")
|
||||
return
|
||||
changeType(n.sons[i].sons[1], f.typ, check)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = n.sons[i]
|
||||
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
||||
addSon(a, newSymNode(newType.n.sons[i].sym))
|
||||
addSon(a, m)
|
||||
changeType(m, newType.sons[i], check)
|
||||
n.sons[i] = a
|
||||
if m.kind == nkExprColonExpr:
|
||||
m = m.sons[1]
|
||||
n.sons[i] = m
|
||||
changeType(m, tup.sons[i], check)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if check:
|
||||
let value = n.intVal
|
||||
|
|
@ -533,7 +529,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
|||
elif skipTypes(it.sons[1].typ, abstractVar).kind in
|
||||
{tyNil, tyArrayConstr, tyTuple, tySet}:
|
||||
var s = skipTypes(it.typ, abstractVar)
|
||||
changeType(it.sons[1], s, check=true)
|
||||
if s.kind != tyExpr:
|
||||
changeType(it.sons[1], s, check=true)
|
||||
n.sons[i] = it.sons[1]
|
||||
of nkBracket:
|
||||
# an implicitly constructed array (passed to an open array):
|
||||
|
|
@ -721,7 +718,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
|||
case callee.kind
|
||||
of skMacro, skTemplate: discard
|
||||
else:
|
||||
if (callee.kind in skIterators) and (callee.id == c.p.owner.id):
|
||||
if callee.kind in skIterators and callee.id == c.p.owner.id:
|
||||
localError(n.info, errRecursiveDependencyX, callee.name.s)
|
||||
if sfNoSideEffect notin callee.flags:
|
||||
if {sfImportc, sfSideEffect} * callee.flags != {}:
|
||||
|
|
@ -832,45 +829,17 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
if result != nil: result = afterCallActions(c, result, nOrig, flags)
|
||||
else: result = errorNode(c, n)
|
||||
|
||||
proc buildStringify(c: PContext, arg: PNode): PNode =
|
||||
if arg.typ != nil and
|
||||
skipTypes(arg.typ, abstractInst-{tyTypeDesc}).kind == tyString:
|
||||
result = arg
|
||||
else:
|
||||
result = newNodeI(nkCall, arg.info)
|
||||
addSon(result, newIdentNode(getIdent"$", arg.info))
|
||||
addSon(result, arg)
|
||||
|
||||
proc semEcho(c: PContext, n: PNode): PNode =
|
||||
# this really is a macro
|
||||
checkMinSonsLen(n, 1)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var arg = semExprWithType(c, n.sons[i])
|
||||
arg = semExprWithType(c, buildStringify(c, arg))
|
||||
n.sons[i] = arg
|
||||
let t = arg.typ
|
||||
if (t == nil or t.skipTypes(abstractInst).kind != tyString) and
|
||||
arg.kind != nkEmpty:
|
||||
localError(n.info, errGenerated,
|
||||
"implicitly invoked '$' does not return string")
|
||||
let t = n.sons[0].typ
|
||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||
result = n
|
||||
|
||||
proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||
# we MUST not check 'n' for semantics again here!
|
||||
# we MUST not check 'n' for semantics again here! But for now we give up:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
|
||||
if e != nil:
|
||||
addSon(result, newSymNode(e))
|
||||
add(result, newSymNode(e))
|
||||
else:
|
||||
localError(n.info, errSystemNeeds, "echo")
|
||||
addSon(result, errorNode(c, n))
|
||||
var arg = buildStringify(c, n)
|
||||
# problem is: implicit '$' is not checked for semantics yet. So we give up
|
||||
# and check 'arg' for semantics again:
|
||||
arg = semExpr(c, arg)
|
||||
if arg != nil: addSon(result, arg)
|
||||
add(result, errorNode(c, n))
|
||||
add(result, n)
|
||||
result = semExpr(c, result)
|
||||
|
||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||
result = semExpr(c, n, {efWantStmt})
|
||||
|
|
@ -958,17 +927,18 @@ proc readTypeParameter(c: PContext, typ: PType,
|
|||
paramName: PIdent, info: TLineInfo): PNode =
|
||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
|
||||
|
||||
#debug ty
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
if tParam.sym.name == paramName:
|
||||
if tParam.sym.name.id == paramName.id:
|
||||
let rawTyp = ty.sons[s + 1]
|
||||
if rawTyp.kind == tyStatic:
|
||||
return rawTyp.n
|
||||
else:
|
||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||
#echo "came here: returned nil"
|
||||
|
||||
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
## returns nil if it's not a built-in field access
|
||||
|
|
@ -980,8 +950,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
|
||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if s != nil:
|
||||
markUsed(n.sons[1].info, s)
|
||||
return semSym(c, n, s, flags)
|
||||
if s.kind in OverloadableSyms:
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
if result.kind == nkSym: result = semSym(c, n, s, flags)
|
||||
else:
|
||||
markUsed(n.sons[1].info, s)
|
||||
result = semSym(c, n, s, flags)
|
||||
styleCheckUse(n.sons[1].info, s)
|
||||
return
|
||||
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
|
||||
#restoreOldStyleType(n.sons[0])
|
||||
|
|
@ -997,13 +973,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
if f != nil:
|
||||
result = newSymNode(f)
|
||||
result.info = n.info
|
||||
result.typ = ty
|
||||
markUsed(n.info, f)
|
||||
styleCheckUse(n.info, f)
|
||||
return
|
||||
of tyTypeParamsHolders:
|
||||
return readTypeParameter(c, ty, i, n.info)
|
||||
|
|
@ -1036,12 +1013,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
if fieldVisible(c, f):
|
||||
# is the access to a public field or in the same module or in a friend?
|
||||
markUsed(n.sons[1].info, f)
|
||||
styleCheckUse(n.sons[1].info, f)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
n.sons[1] = newSymNode(f) # we now have the correct field
|
||||
n.typ = f.typ
|
||||
if check == nil:
|
||||
if check == nil:
|
||||
result = n
|
||||
else:
|
||||
else:
|
||||
check.sons[0] = n
|
||||
check.typ = n.typ
|
||||
result = check
|
||||
|
|
@ -1049,6 +1027,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
f = getSymFromList(ty.n, i)
|
||||
if f != nil:
|
||||
markUsed(n.sons[1].info, f)
|
||||
styleCheckUse(n.sons[1].info, f)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
n.sons[1] = newSymNode(f)
|
||||
n.typ = f.typ
|
||||
|
|
@ -1260,8 +1239,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
|||
proc semReturn(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1)
|
||||
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
|
||||
c.p.owner.kind == skClosureIterator:
|
||||
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
|
||||
skClosureIterator}:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
# transform ``return expr`` to ``result = expr; return``
|
||||
if c.p.resultSym != nil:
|
||||
|
|
@ -1444,6 +1423,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
|||
|
||||
proc semUsing(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
if not experimentalMode(c):
|
||||
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
|
||||
for e in n.sons:
|
||||
let usedSym = semExpr(c, e)
|
||||
if usedSym.kind == nkSym:
|
||||
|
|
@ -1465,6 +1446,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
|||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
markUsed(n.info, expandedSym)
|
||||
styleCheckUse(n.info, expandedSym)
|
||||
|
||||
for i in countup(1, macroCall.len-1):
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||
|
|
@ -1525,11 +1507,11 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
|||
|
||||
doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
|
||||
if ids.len > 0:
|
||||
doBlk[paramsPos].sons.setLen(2)
|
||||
doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type
|
||||
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||
doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
|
||||
ids.add getSysSym("expr").newSymNode # params type
|
||||
ids.add emptyNode # no default value
|
||||
doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids)
|
||||
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||
|
||||
var tmpl = semTemplateDef(c, doBlk)
|
||||
quotes[0] = tmpl[namePos]
|
||||
|
|
@ -1538,8 +1520,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
|||
newNode(nkCall, n.info, quotes)])
|
||||
result = semExpandToAst(c, result)
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode =
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# watch out, hacks ahead:
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
let oldErrorMax = msgs.gErrorMax
|
||||
|
|
@ -1553,7 +1534,7 @@ proc tryExpr(c: PContext, n: PNode,
|
|||
let oldOwnerLen = len(gOwners)
|
||||
let oldGenerics = c.generics
|
||||
let oldErrorOutputs = errorOutputs
|
||||
errorOutputs = if bufferErrors: {eInMemory} else: {}
|
||||
errorOutputs = {}
|
||||
let oldContextLen = msgs.getInfoContextLen()
|
||||
|
||||
let oldInGenericContext = c.inGenericContext
|
||||
|
|
@ -1638,7 +1619,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
||||
of mIs: result = semIs(c, setMs(n, s))
|
||||
of mOf: result = semOf(c, setMs(n, s))
|
||||
of mEcho: result = semEcho(c, setMs(n, s))
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
||||
of mQuoteAst: result = semQuoteAst(c, n)
|
||||
|
|
@ -1662,6 +1642,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
else:
|
||||
result.typ = result[1].typ
|
||||
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
||||
of mProcCall:
|
||||
result = setMs(n, s)
|
||||
result.sons[1] = semExpr(c, n.sons[1])
|
||||
result.typ = n[1].typ
|
||||
else: result = semDirectOp(c, n, flags)
|
||||
|
||||
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
|
|
@ -1821,7 +1805,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||
result.typ = typ
|
||||
|
||||
proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) =
|
||||
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
|
|
@ -1902,6 +1886,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
|||
addDecl(c, labl)
|
||||
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
||||
suggestSym(n.sons[0].info, labl)
|
||||
styleCheckDef(labl)
|
||||
n.sons[1] = semExpr(c, n.sons[1])
|
||||
n.typ = n.sons[1].typ
|
||||
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
||||
|
|
@ -1909,19 +1894,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
|||
closeScope(c)
|
||||
dec(c.p.nestedBlockCounter)
|
||||
|
||||
proc doBlockIsStmtList(n: PNode): bool =
|
||||
result = n.kind == nkDo and
|
||||
n[paramsPos].sonsLen == 1 and
|
||||
n[paramsPos][0].kind == nkEmpty
|
||||
|
||||
proc fixImmediateParams(n: PNode): PNode =
|
||||
# XXX: Temporary work-around until we carry out
|
||||
# the planned overload resolution reforms
|
||||
for i in 1 .. <safeLen(n):
|
||||
if doBlockIsStmtList(n[i]):
|
||||
n.sons[i] = n[i][bodyPos]
|
||||
result = n
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
var x = newNodeI(n.kind, n.info)
|
||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
||||
|
|
@ -1930,13 +1902,23 @@ proc semExport(c: PContext, n: PNode): PNode =
|
|||
var o: TOverloadIter
|
||||
var s = initOverloadIter(o, c, a)
|
||||
if s == nil:
|
||||
localError(a.info, errGenerated, "invalid expr for 'export': " &
|
||||
renderTree(a))
|
||||
while s != nil:
|
||||
if s.kind in ExportableSymKinds+{skModule}:
|
||||
x.add(newSymNode(s, a.info))
|
||||
strTableAdd(c.module.tab, s)
|
||||
s = nextOverloadIter(o, c, a)
|
||||
localError(a.info, errGenerated, "cannot export: " & renderTree(a))
|
||||
elif s.kind == skModule:
|
||||
# forward everything from that module:
|
||||
strTableAdd(c.module.tab, s)
|
||||
x.add(newSymNode(s, a.info))
|
||||
var ti: TTabIter
|
||||
var it = initTabIter(ti, s.tab)
|
||||
while it != nil:
|
||||
if it.kind in ExportableSymKinds+{skModule}:
|
||||
strTableAdd(c.module.tab, it)
|
||||
it = nextIter(ti, s.tab)
|
||||
else:
|
||||
while s != nil:
|
||||
if s.kind in ExportableSymKinds+{skModule}:
|
||||
x.add(newSymNode(s, a.info))
|
||||
strTableAdd(c.module.tab, s)
|
||||
s = nextOverloadIter(o, c, a)
|
||||
when false:
|
||||
if c.module.ast.isNil:
|
||||
c.module.ast = newNodeI(nkStmtList, n.info)
|
||||
|
|
@ -2021,22 +2003,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
checkMinSonsLen(n, 1)
|
||||
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
|
||||
var s = qualifiedLookUp(c, n.sons[0], mode)
|
||||
if s != nil:
|
||||
if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
|
||||
pretty.checkUse(n.sons[0].sons[1].info, s)
|
||||
if s != nil:
|
||||
#if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
|
||||
# pretty.checkUse(n.sons[0].sons[1].info, s)
|
||||
case s.kind
|
||||
of skMacro:
|
||||
if sfImmediate notin s.flags:
|
||||
result = semDirectOp(c, n, flags)
|
||||
else:
|
||||
var p = fixImmediateParams(n)
|
||||
result = semMacroExpr(c, p, p, s, flags)
|
||||
result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate:
|
||||
if sfImmediate notin s.flags:
|
||||
result = semDirectOp(c, n, flags)
|
||||
else:
|
||||
var p = fixImmediateParams(n)
|
||||
result = semTemplateExpr(c, p, s, flags)
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skType:
|
||||
# XXX think about this more (``set`` procs)
|
||||
if n.len == 2:
|
||||
|
|
|
|||
163
compiler/semfields.nim
Normal file
163
compiler/semfields.nim
Normal 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
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -197,18 +197,20 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|||
of mSubI, mSubI64, mSubU:
|
||||
binaryOp(`|-|`)
|
||||
of mBitandI, mBitandI64:
|
||||
# since uint64 is still not even valid for 'range' (since it's no ordinal
|
||||
# yet), we exclude it from the list (see bug #1638) for now:
|
||||
var a = n.sons[1]
|
||||
var b = n.sons[2]
|
||||
# symmetrical:
|
||||
if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b)
|
||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
|
||||
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||
let x = b.intVal|+|1
|
||||
if (x and -x) == x and x >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal)
|
||||
of mModU:
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||
if b.intVal >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal-1)
|
||||
else:
|
||||
|
|
@ -255,6 +257,7 @@ proc evalIs(n, a: PNode): PNode =
|
|||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||
t.callConv == ccClosure and
|
||||
tfIterator in t.flags))
|
||||
else: discard
|
||||
else:
|
||||
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
||||
let t2 = n[2].typ
|
||||
|
|
@ -318,8 +321,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||
else: internalError(n.info, "constant folding for shr")
|
||||
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
|
||||
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
|
||||
of mDivI, mDivI64:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(getInt(a) div y, n)
|
||||
of mModI, mModI64:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(getInt(a) mod y, n)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
||||
|
|
@ -358,8 +367,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
|||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
|
||||
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
|
||||
of mModU:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(`%%`(getInt(a), y), n)
|
||||
of mDivU:
|
||||
let y = getInt(b)
|
||||
if y != 0:
|
||||
result = newIntNodeT(`/%`(getInt(a), y), n)
|
||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
||||
of mLtSet:
|
||||
|
|
@ -501,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
|
|||
of tyInt..tyInt64:
|
||||
case skipTypes(a.typ, abstractRange).kind
|
||||
of tyFloat..tyFloat64:
|
||||
result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||
result = newIntNodeT(int(getFloat(a)), n)
|
||||
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
||||
else:
|
||||
result = a
|
||||
|
|
@ -600,10 +615,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
|||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
||||
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
||||
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
|
||||
of mNimrodVersion: result = newStrNodeT(VersionAsString, n)
|
||||
of mNimrodMajor: result = newIntNodeT(VersionMajor, n)
|
||||
of mNimrodMinor: result = newIntNodeT(VersionMinor, n)
|
||||
of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
|
||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
||||
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
|
||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
|
||||
|
|
@ -683,9 +694,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
|||
result = evalIs(n, a)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
except EOverflow:
|
||||
except OverflowError:
|
||||
localError(n.info, errOverOrUnderflow)
|
||||
except EDivByZero:
|
||||
except DivByZeroError:
|
||||
localError(n.info, errConstantDivisionByZero)
|
||||
of nkAddr:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
# A problem is that it cannot be detected if the symbol is introduced
|
||||
# as in ``var x = ...`` or used because macros/templates can hide this!
|
||||
# So we have to eval templates/macros right here so that symbol
|
||||
# lookup can be accurate. XXX But this can only be done for immediate macros!
|
||||
# lookup can be accurate.
|
||||
|
||||
# included from sem.nim
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode =
|
|||
|
||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode =
|
||||
ctx: var IntSet): PNode =
|
||||
openScope(c)
|
||||
result = semGenericStmt(c, n, flags, ctx)
|
||||
closeScope(c)
|
||||
|
|
@ -37,7 +37,7 @@ template macroToExpand(s: expr): expr =
|
|||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
||||
|
||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
ctx: var TIntSet): PNode =
|
||||
ctx: var IntSet): PNode =
|
||||
incl(s.flags, sfUsed)
|
||||
case s.kind
|
||||
of skUnknown:
|
||||
|
|
@ -47,33 +47,39 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
|||
result = symChoice(c, n, s, scOpen)
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
styleCheckUse(n.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skMacro:
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
styleCheckUse(n.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
of skParam:
|
||||
styleCheckUse(n.info, s)
|
||||
of skParam:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
of skType:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else:
|
||||
result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode =
|
||||
ctx: var IntSet): PNode =
|
||||
result = n
|
||||
let ident = considerQuotedIdent(n)
|
||||
var s = searchInScopes(c, ident)
|
||||
var s = searchInScopes(c, ident).skipAlias(n)
|
||||
if s == nil:
|
||||
if ident.id notin ctx and withinMixin notin flags:
|
||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
|
|
@ -92,7 +98,7 @@ proc newDot(n, b: PNode): PNode =
|
|||
result.add(b)
|
||||
|
||||
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var TIntSet): PNode =
|
||||
ctx: var IntSet; isMacro: var bool): PNode =
|
||||
assert n.kind == nkDotExpr
|
||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||
|
||||
|
|
@ -104,8 +110,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
|||
result = n
|
||||
let n = n[1]
|
||||
let ident = considerQuotedIdent(n)
|
||||
var s = searchInScopes(c, ident)
|
||||
var s = searchInScopes(c, ident).skipAlias(n)
|
||||
if s != nil and s.kind in routineKinds:
|
||||
isMacro = s.kind in {skTemplate, skMacro}
|
||||
if withinBind in flags:
|
||||
result = newDot(result, symChoice(c, n, s, scClosed))
|
||||
elif s.name.id in ctx:
|
||||
|
|
@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
|||
else:
|
||||
result = newDot(result, sym)
|
||||
|
||||
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
let s = newSymS(skUnknown, getIdentNode(n), c)
|
||||
addPrelimDecl(c, s)
|
||||
styleCheckDef(n.info, s, kind)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var TIntSet): PNode =
|
||||
flags: TSemGenericFlags, ctx: var IntSet): PNode =
|
||||
result = n
|
||||
if gCmd == cmdIdeTools: suggestStmt(c, n)
|
||||
case n.kind
|
||||
|
|
@ -129,7 +141,8 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
#var s = qualifiedLookUp(c, n, luf)
|
||||
#if s != nil: result = semGenericStmtSymbol(c, n, s)
|
||||
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
|
||||
result = fuzzyLookup(c, n, flags, ctx)
|
||||
var dummy: bool
|
||||
result = fuzzyLookup(c, n, flags, ctx, dummy)
|
||||
of nkEmpty, nkSym..nkNilLit:
|
||||
# see tests/compile/tgensymgeneric.nim:
|
||||
# We need to open the gensym'ed symbol again so that the instantiation
|
||||
|
|
@ -153,50 +166,61 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||
|
||||
var first = 0
|
||||
var isDefinedMagic = false
|
||||
if s != nil:
|
||||
var mixinContext = false
|
||||
if s != nil:
|
||||
incl(s.flags, sfUsed)
|
||||
isDefinedMagic = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
||||
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
||||
let scOption = if s.name.id in ctx: scForceOpen else: scOpen
|
||||
case s.kind
|
||||
of skMacro:
|
||||
if macroToExpand(s):
|
||||
styleCheckUse(fn.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||
result = n
|
||||
of skTemplate:
|
||||
mixinContext = true
|
||||
of skTemplate:
|
||||
if macroToExpand(s):
|
||||
let n = fixImmediateParams(n)
|
||||
styleCheckUse(fn.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||
result = n
|
||||
# BUGFIX: we must not return here, we need to do first phase of
|
||||
# symbol lookup ...
|
||||
# symbol lookup. Also since templates and macros can do scope injections
|
||||
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
|
||||
# the famous "undeclared identifier: it" bug:
|
||||
mixinContext = true
|
||||
of skUnknown, skParam:
|
||||
# Leave it as an identifier.
|
||||
discard
|
||||
of skProc, skMethod, skIterators, skConverter:
|
||||
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
||||
result.sons[0] = symChoice(c, fn, s, scOption)
|
||||
first = 1
|
||||
of skGenericParam:
|
||||
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
of skType:
|
||||
# bad hack for generics:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
else:
|
||||
result.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
result.sons[0] = newSymNode(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
first = 1
|
||||
elif fn.kind == nkDotExpr:
|
||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||
first = 1
|
||||
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||
let flags = if isDefinedMagic: flags+{withinMixin} else: flags
|
||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||
for i in countup(first, sonsLen(result) - 1):
|
||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||
of nkIfStmt:
|
||||
|
|
@ -226,14 +250,14 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
openScope(c)
|
||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||
for i in countup(0, L - 3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c))
|
||||
addTempDecl(c, n.sons[i], skForVar)
|
||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c))
|
||||
addTempDecl(c, n.sons[0], skLabel)
|
||||
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
closeScope(c)
|
||||
of nkTryStmt:
|
||||
|
|
@ -256,7 +280,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
||||
of nkGenericParams:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
|
|
@ -266,23 +290,23 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
# do not perform symbol lookup for default expressions
|
||||
for j in countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
||||
of nkConstSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
||||
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||
of nkTypeSection:
|
||||
of nkTypeSection:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
||||
addTempDecl(c, getIdentNode(a.sons[0]), skType)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
|
|
@ -306,9 +330,9 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
of nkIdent: a = n.sons[i]
|
||||
else: illFormedAst(n)
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||
of nkObjectTy, nkTupleTy:
|
||||
of nkObjectTy, nkTupleTy:
|
||||
discard
|
||||
of nkFormalParams:
|
||||
of nkFormalParams:
|
||||
checkMinSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||
|
|
@ -320,17 +344,17 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||
for j in countup(0, L-3):
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
||||
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||
nkIteratorDef, nkLambdaKinds:
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
if n.kind notin nkLambdaKinds:
|
||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
|
||||
if n.sons[namePos].kind != nkEmpty:
|
||||
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
||||
openScope(c)
|
||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||
flags, ctx)
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -157,8 +157,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
|||
#
|
||||
# The solution would be to move this logic into semtypinst, but
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc
|
||||
#
|
||||
# will need to use openScope, addDecl, etc.
|
||||
addDecl(c, prc)
|
||||
|
||||
pushInfoContext(info)
|
||||
|
|
@ -223,7 +222,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
var oldPrc = genericCacheGet(fn, entry[])
|
||||
if oldPrc == nil:
|
||||
fn.procInstCache.safeAdd(entry)
|
||||
# we MUST not add potentially wrong instantiations to the caching mechanism.
|
||||
# This means recursive instantiations behave differently when in
|
||||
# a ``compiles`` context but this is the lesser evil. See
|
||||
# bug #1055 (tevilcompiles).
|
||||
if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry)
|
||||
c.generics.add(makeInstPair(fn, entry))
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -55,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) =
|
|||
else:
|
||||
globalError(n.info, "() must have an object or tuple type")
|
||||
of nkBracket:
|
||||
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
|
||||
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}:
|
||||
n.typ = t
|
||||
for m in n: annotateType(m, x.elemType)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -130,4 +130,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
|||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mNBindSym: result = semBindSym(c, n)
|
||||
of mLocals: result = semLocals(c, n)
|
||||
of mProcCall:
|
||||
result = n
|
||||
result.typ = n[1].typ
|
||||
else: result = n
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -258,14 +258,18 @@ proc min(a, b: PNode): PNode =
|
|||
|
||||
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
||||
|
||||
template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
|
||||
inc c.spawns
|
||||
let oldSpawnId = c.currentSpawnId
|
||||
c.currentSpawnId = c.spawns
|
||||
body
|
||||
c.currentSpawnId = oldSpawnId
|
||||
|
||||
proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
|
||||
if op.magic == mSpawn:
|
||||
inc c.spawns
|
||||
let oldSpawnId = c.currentSpawnId
|
||||
c.currentSpawnId = c.spawns
|
||||
gatherArgs(c, n[1])
|
||||
analyseSons(c, n)
|
||||
c.currentSpawnId = oldSpawnId
|
||||
pushSpawnId(c):
|
||||
gatherArgs(c, n[1])
|
||||
analyseSons(c, n)
|
||||
elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
|
||||
if n[1].isLocal:
|
||||
let incr = n[2].skipConv
|
||||
|
|
@ -320,9 +324,16 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
|||
# since we already ensure sfAddrTaken is not in s.flags, we only need to
|
||||
# prevent direct assignments to the monotonic variable:
|
||||
let slot = c.getSlot(n[0].sym)
|
||||
slot.blackListed = true
|
||||
slot.blacklisted = true
|
||||
invalidateFacts(c.guards, n[0])
|
||||
analyseSons(c, n)
|
||||
let value = n[1]
|
||||
if getMagic(value) == mSpawn:
|
||||
pushSpawnId(c):
|
||||
gatherArgs(c, value[1])
|
||||
analyseSons(c, value[1])
|
||||
analyse(c, n[0])
|
||||
else:
|
||||
analyseSons(c, n)
|
||||
addAsgnFact(c.guards, n[0], n[1])
|
||||
of nkCallKinds:
|
||||
# direct call:
|
||||
|
|
@ -335,16 +346,21 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
|||
localError(n.info, "invalid control flow for 'parallel'")
|
||||
# 'break' that leaves the 'parallel' section is not valid either
|
||||
# or maybe we should generate a 'try' XXX
|
||||
of nkVarSection:
|
||||
of nkVarSection, nkLetSection:
|
||||
for it in n:
|
||||
let value = it.lastSon
|
||||
let isSpawned = getMagic(value) == mSpawn
|
||||
if isSpawned:
|
||||
pushSpawnId(c):
|
||||
gatherArgs(c, value[1])
|
||||
analyseSons(c, value[1])
|
||||
if value.kind != nkEmpty:
|
||||
for j in 0 .. it.len-3:
|
||||
if it[j].isLocal:
|
||||
let slot = c.getSlot(it[j].sym)
|
||||
if slot.lower.isNil: slot.lower = value
|
||||
else: internalError(it.info, "slot already has a lower bound")
|
||||
analyse(c, value)
|
||||
if not isSpawned: analyse(c, value)
|
||||
of nkCaseStmt: analyseCase(c, n)
|
||||
of nkIfStmt, nkIfExpr: analyseIf(c, n)
|
||||
of nkWhileStmt:
|
||||
|
|
@ -396,7 +412,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
|
|||
|
||||
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
|
||||
case n.kind
|
||||
of nkVarSection:
|
||||
of nkVarSection, nkLetSection:
|
||||
result = nil
|
||||
for it in n:
|
||||
let b = it.lastSon
|
||||
|
|
@ -464,6 +480,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
|
|||
result = newNodeI(nkStmtList, n.info)
|
||||
generateAliasChecks(a, result)
|
||||
result.add varSection
|
||||
result.add callCodeGenProc("openBarrier", barrier)
|
||||
result.add callCodegenProc("openBarrier", barrier)
|
||||
result.add transformSpawn(owner, body, barrier)
|
||||
result.add callCodeGenProc("closeBarrier", barrier)
|
||||
result.add callCodegenProc("closeBarrier", barrier)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -57,30 +57,125 @@ discard """
|
|||
c()
|
||||
|
||||
--> we need a stack of scopes for this analysis
|
||||
"""
|
||||
|
||||
const trackGlobals = false ## we don't need it for now
|
||||
# XXX enhance the algorithm to care about 'dirty' expressions:
|
||||
lock a[i].L:
|
||||
inc i # mark 'i' dirty
|
||||
lock a[j].L:
|
||||
access a[i], a[j] # --> reject a[i]
|
||||
"""
|
||||
|
||||
type
|
||||
TEffects = object
|
||||
exc: PNode # stack of exceptions
|
||||
tags: PNode # list of tags
|
||||
uses: PNode # list of used global variables
|
||||
bottom: int
|
||||
bottom, inTryStmt: int
|
||||
owner: PSym
|
||||
init: seq[int] # list of initialized variables
|
||||
guards: TModel # nested guards
|
||||
locked: seq[PNode] # locked locations
|
||||
gcUnsafe, isRecursive: bool
|
||||
gcUnsafe, isRecursive, isToplevel: bool
|
||||
maxLockLevel, currLockLevel: TLockLevel
|
||||
PEffects = var TEffects
|
||||
|
||||
proc `<`(a, b: TLockLevel): bool {.borrow.}
|
||||
proc `<=`(a, b: TLockLevel): bool {.borrow.}
|
||||
proc `==`(a, b: TLockLevel): bool {.borrow.}
|
||||
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
||||
|
||||
proc isLocalVar(a: PEffects, s: PSym): bool =
|
||||
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
|
||||
|
||||
proc initVar(a: PEffects, n: PNode) =
|
||||
proc getLockLevel(t: PType): TLockLevel =
|
||||
var t = t
|
||||
# tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
|
||||
if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
|
||||
if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
|
||||
result = t.n.intVal.TLockLevel
|
||||
|
||||
proc lockLocations(a: PEffects; pragma: PNode) =
|
||||
if pragma.kind != nkExprColonExpr:
|
||||
localError(pragma.info, errGenerated, "locks pragma without argument")
|
||||
return
|
||||
var firstLL = TLockLevel(-1'i16)
|
||||
for x in pragma[1]:
|
||||
let thisLL = getLockLevel(x.typ)
|
||||
if thisLL != 0.TLockLevel:
|
||||
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
|
||||
localError(x.info, "invalid lock level: " & $thisLL)
|
||||
elif firstLL < 0.TLockLevel: firstLL = thisLL
|
||||
elif firstLL != thisLL:
|
||||
localError(x.info, errGenerated,
|
||||
"multi-lock requires the same static lock level for every operand")
|
||||
a.maxLockLevel = max(a.maxLockLevel, firstLL)
|
||||
a.locked.add x
|
||||
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
|
||||
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
|
||||
localError(pragma.info, errGenerated,
|
||||
"invalid nested locking")
|
||||
a.currLockLevel = firstLL
|
||||
|
||||
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
|
||||
# check whether the corresponding lock is held:
|
||||
for L in a.locked:
|
||||
if L.kind == nkSym and L.sym == guard: return
|
||||
# we allow accesses nevertheless in top level statements for
|
||||
# easier initialization:
|
||||
#if a.isTopLevel:
|
||||
# message(n.info, warnUnguardedAccess, renderTree(n))
|
||||
#else:
|
||||
if not a.isTopLevel:
|
||||
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||
|
||||
# 'guard*' are checks which are concerned with 'guard' annotations
|
||||
# (var x{.guard: y.}: int)
|
||||
proc guardDotAccess(a: PEffects; n: PNode) =
|
||||
let ri = n.sons[1]
|
||||
if ri.kind != nkSym or ri.sym.kind != skField: return
|
||||
var g = ri.sym.guard
|
||||
if g.isNil or a.isTopLevel: return
|
||||
# fixup guard:
|
||||
if g.kind == skUnknown:
|
||||
var field: PSym = nil
|
||||
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
||||
if ty.kind == tyTuple:
|
||||
field = lookupInRecord(ty.n, g.name)
|
||||
else:
|
||||
while ty != nil and ty.kind == tyObject:
|
||||
field = lookupInRecord(ty.n, g.name)
|
||||
if field != nil: break
|
||||
ty = ty.sons[0]
|
||||
if ty == nil: break
|
||||
ty = ty.skipTypes(abstractPtrs)
|
||||
if field == nil:
|
||||
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
|
||||
return
|
||||
g = field
|
||||
#ri.sym.guard = field
|
||||
# XXX unfortunately this is not correct for generic instantiations!
|
||||
if g.kind == skField:
|
||||
let dot = newNodeI(nkDotExpr, n.info, 2)
|
||||
dot.sons[0] = n.sons[0]
|
||||
dot.sons[1] = newSymNode(g)
|
||||
dot.typ = g.typ
|
||||
for L in a.locked:
|
||||
#if a.guards.sameSubexprs(dot, L): return
|
||||
if guards.sameTree(dot, L): return
|
||||
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||
else:
|
||||
guardGlobal(a, n, g)
|
||||
|
||||
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
|
||||
template compileToCpp(a): expr =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
|
||||
if a.inTryStmt > 0 and not compileToCpp(a):
|
||||
incl(s.flags, sfVolatile)
|
||||
|
||||
proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
|
||||
if n.kind != nkSym: return
|
||||
let s = n.sym
|
||||
if isLocalVar(a, s):
|
||||
if volatileCheck: makeVolatile(a, s)
|
||||
for x in a.init:
|
||||
if x == s.id: return
|
||||
a.init.add s.id
|
||||
|
|
@ -91,14 +186,13 @@ proc initVarViaNew(a: PEffects, n: PNode) =
|
|||
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
|
||||
# 'x' is not nil, but that doesn't mean its "not nil" children
|
||||
# are initialized:
|
||||
initVar(a, n)
|
||||
initVar(a, n, volatileCheck=true)
|
||||
elif isLocalVar(a, s):
|
||||
makeVolatile(a, s)
|
||||
|
||||
when trackGlobals:
|
||||
proc addUse(a: PEffects, e: PNode) =
|
||||
var aa = a.uses
|
||||
for i in 0 .. <aa.len:
|
||||
if aa[i].sym.id == e.sym.id: return
|
||||
a.uses.add(e)
|
||||
proc warnAboutGcUnsafe(n: PNode) =
|
||||
#assert false
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
|
|
@ -110,12 +204,11 @@ proc useVar(a: PEffects, n: PNode) =
|
|||
message(n.info, warnUninit, s.name.s)
|
||||
# prevent superfluous warnings about the same variable:
|
||||
a.init.add s.id
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar:
|
||||
when trackGlobals:
|
||||
a.addUse(copyNode(n))
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
|
||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||
tfGcSafe notin s.typ.flags:
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
a.gcUnsafe = true
|
||||
|
||||
type
|
||||
|
|
@ -130,20 +223,27 @@ proc addToIntersection(inter: var TIntersection, s: int) =
|
|||
|
||||
proc throws(tracked, n: PNode) =
|
||||
if n.typ == nil or n.typ.kind != tyError: tracked.add n
|
||||
|
||||
|
||||
proc getEbase(): PType =
|
||||
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
|
||||
else: sysTypeFromName"E_Base"
|
||||
|
||||
proc excType(n: PNode): PType =
|
||||
# reraise is like raising E_Base:
|
||||
let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ
|
||||
let t = if n.kind == nkEmpty: getEbase() else: n.typ
|
||||
result = skipTypes(t, skipPtrs)
|
||||
|
||||
proc createRaise(n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
result.typ = sysTypeFromName"E_Base"
|
||||
result.typ = getEbase()
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc createTag(n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
result.typ = sysTypeFromName"TEffect"
|
||||
if getCompilerProc("RootEffect") != nil:
|
||||
result.typ = sysTypeFromName"RootEffect"
|
||||
else:
|
||||
result.typ = sysTypeFromName"TEffect"
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc createAnyGlobal(n: PNode): PNode =
|
||||
|
|
@ -179,17 +279,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) =
|
|||
else:
|
||||
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
|
||||
|
||||
when trackGlobals:
|
||||
proc mergeUses(a: PEffects, b, comesFrom: PNode) =
|
||||
if b.isNil:
|
||||
addUse(a, createAnyGlobal(comesFrom))
|
||||
else:
|
||||
for effect in items(b): addUse(a, effect)
|
||||
|
||||
proc listEffects(a: PEffects) =
|
||||
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.uses): message(e.info, hintUser, e.sym.name.s)
|
||||
#if a.maxLockLevel != 0:
|
||||
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
|
||||
|
||||
proc catches(tracked: PEffects, e: PType) =
|
||||
let e = skipTypes(e, skipPtrs)
|
||||
|
|
@ -219,7 +313,9 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
|||
let oldState = tracked.init.len
|
||||
var inter: TIntersection = @[]
|
||||
|
||||
track(tracked, n.sons[0])
|
||||
inc tracked.inTryStmt
|
||||
track(tracked, n.sons[0])
|
||||
dec tracked.inTryStmt
|
||||
for i in oldState.. <tracked.init.len:
|
||||
addToIntersection(inter, tracked.init[i])
|
||||
|
||||
|
|
@ -274,7 +370,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
|
|||
# list the computed effects up to here:
|
||||
listEffects(tracked)
|
||||
|
||||
proc effectSpec(n: PNode, effectType = wRaises): PNode =
|
||||
proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
|
||||
|
|
@ -284,8 +380,7 @@ proc effectSpec(n: PNode, effectType = wRaises): PNode =
|
|||
result.add(it.sons[1])
|
||||
return
|
||||
|
||||
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
|
||||
var x = x
|
||||
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
|
||||
let spec = effectSpec(x, effectType)
|
||||
if isNil(spec):
|
||||
let s = n.sons[namePos].sym
|
||||
|
|
@ -303,18 +398,20 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
|
|||
# set the type so that the following analysis doesn't screw up:
|
||||
effects.sons[i].typ = real[i].typ
|
||||
|
||||
var pair = newNode(nkExprColonExpr, n.info, @[
|
||||
result = newNode(nkExprColonExpr, n.info, @[
|
||||
newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
|
||||
|
||||
if x.kind == nkEmpty:
|
||||
x = newNodeI(nkPragma, n.info)
|
||||
n.sons[pragmasPos] = x
|
||||
x.add(pair)
|
||||
|
||||
proc documentRaises*(n: PNode) =
|
||||
if n.sons[namePos].kind != nkSym: return
|
||||
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
||||
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
||||
let pragmas = n.sons[pragmasPos]
|
||||
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
|
||||
let p2 = documentEffect(n, pragmas, wTags, tagEffects)
|
||||
|
||||
if p1 != nil or p2 != nil:
|
||||
if pragmas.kind == nkEmpty:
|
||||
n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
|
||||
if p1 != nil: n.sons[pragmasPos].add p1
|
||||
if p2 != nil: n.sons[pragmasPos].add p2
|
||||
|
||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||
|
||||
|
|
@ -322,6 +419,25 @@ proc importedFromC(n: PNode): bool =
|
|||
# when imported from C, we assume GC-safety.
|
||||
result = n.kind == nkSym and sfImportc in n.sym.flags
|
||||
|
||||
proc getLockLevel(s: PSym): TLockLevel =
|
||||
result = s.typ.lockLevel
|
||||
if result == UnspecifiedLockLevel:
|
||||
if {sfImportc, sfNoSideEffect} * s.flags != {} or
|
||||
tfNoSideEffect in s.typ.flags:
|
||||
result = 0.TLockLevel
|
||||
else:
|
||||
result = UnknownLockLevel
|
||||
#message(s.info, warnUser, "FOR THIS " & s.name.s)
|
||||
|
||||
proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
|
||||
if lockLevel >= tracked.currLockLevel:
|
||||
# if in lock section:
|
||||
if tracked.currLockLevel > 0.TLockLevel:
|
||||
localError n.info, errGenerated,
|
||||
"expected lock level < " & $tracked.currLockLevel &
|
||||
" but got lock level " & $lockLevel
|
||||
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
|
||||
|
||||
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
let pragma = s.ast.sons[pragmasPos]
|
||||
let spec = effectSpec(pragma, wRaises)
|
||||
|
|
@ -331,8 +447,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
|||
mergeTags(tracked, tagSpec, n)
|
||||
|
||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let n = n.skipConv
|
||||
|
|
@ -352,8 +469,22 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
|||
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
|
||||
of impYes: discard
|
||||
|
||||
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
|
||||
else: op.lockLevel
|
||||
#if lockLevel == UnknownLockLevel:
|
||||
# message(n.info, warnUser, "had to assume the worst here")
|
||||
mergeLockLevels(tracked, n, lockLevel)
|
||||
|
||||
proc isOwnedProcVar(n: PNode; owner: PSym): bool =
|
||||
# XXX prove the soundness of this effect system rule
|
||||
result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
|
||||
|
||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let op = skipConvAndClosure(n).typ
|
||||
let a = skipConvAndClosure(n)
|
||||
let op = a.typ
|
||||
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
|
||||
internalAssert op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
|
|
@ -365,21 +496,18 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
|||
# we have no explicit effects but it's a forward declaration and so it's
|
||||
# stated there are no additional effects, so simply propagate them:
|
||||
propagateEffects(tracked, n, n.sym)
|
||||
else:
|
||||
elif not isOwnedProcVar(a, tracked.owner):
|
||||
# we have no explicit effects so assume the worst:
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
||||
assumeTheWorst(tracked, n, op)
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
else:
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
|
|
@ -494,7 +622,8 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
useVar(tracked, n)
|
||||
of nkRaiseStmt:
|
||||
n.sons[0].info = n.info
|
||||
throws(tracked.exc, n.sons[0])
|
||||
#throws(tracked.exc, n.sons[0])
|
||||
addEffect(tracked, n.sons[0], useLineInfo=false)
|
||||
for i in 0 .. <safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkCallKinds:
|
||||
|
|
@ -506,8 +635,12 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
# are indistinguishable from normal procs (both have tyProc type) and
|
||||
# we can detect them only by checking for attached nkEffectList.
|
||||
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
|
||||
if a.kind == nkSym and a.sym == tracked.owner:
|
||||
tracked.isRecursive = true
|
||||
if a.kind == nkSym:
|
||||
if a.sym == tracked.owner: tracked.isRecursive = true
|
||||
# even for recursive calls we need to check the lock levels (!):
|
||||
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
||||
else:
|
||||
mergeLockLevels(tracked, n, op.lockLevel)
|
||||
var effectList = op.n.sons[0]
|
||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
|
|
@ -515,18 +648,14 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
if isForwardedProc(a):
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
elif isIndirectCall(a, tracked.owner):
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
||||
# XXX handle 'gcsafe' properly for callbacks!
|
||||
assumeTheWorst(tracked, n, op)
|
||||
else:
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
||||
if notGcSafe(op) and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
|
|
@ -534,6 +663,9 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
initVarViaNew(tracked, n.sons[1])
|
||||
for i in 0 .. <safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
guardDotAccess(tracked, n)
|
||||
for i in 0 .. <len(n): track(tracked, n.sons[i])
|
||||
of nkCheckedFieldExpr:
|
||||
track(tracked, n.sons[0])
|
||||
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
|
||||
|
|
@ -541,19 +673,19 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
of nkPragma: trackPragmaStmt(tracked, n)
|
||||
of nkAsgn, nkFastAsgn:
|
||||
track(tracked, n.sons[1])
|
||||
initVar(tracked, n.sons[0])
|
||||
initVar(tracked, n.sons[0], volatileCheck=true)
|
||||
invalidateFacts(tracked.guards, n.sons[0])
|
||||
track(tracked, n.sons[0])
|
||||
addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
|
||||
notNilCheck(tracked, n.sons[1], n.sons[0].typ)
|
||||
when false: cstringCheck(tracked, n)
|
||||
of nkVarSection:
|
||||
of nkVarSection, nkLetSection:
|
||||
for child in n:
|
||||
let last = lastSon(child)
|
||||
if child.kind == nkIdentDefs and last.kind != nkEmpty:
|
||||
track(tracked, last)
|
||||
for i in 0 .. child.len-3:
|
||||
initVar(tracked, child.sons[i])
|
||||
initVar(tracked, child.sons[i], volatileCheck=false)
|
||||
addAsgnFact(tracked.guards, child.sons[i], last)
|
||||
notNilCheck(tracked, last, child.sons[i].typ)
|
||||
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
||||
|
|
@ -589,6 +721,16 @@ proc track(tracked: PEffects, n: PNode) =
|
|||
if sfDiscriminant in x.sons[0].sym.flags:
|
||||
addDiscriminantFact(tracked.guards, x)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
of nkPragmaBlock:
|
||||
let pragmaList = n.sons[0]
|
||||
let oldLocked = tracked.locked.len
|
||||
let oldLockLevel = tracked.currLockLevel
|
||||
for i in 0 .. <pragmaList.len:
|
||||
if whichPragma(pragmaList.sons[i]) == wLocks:
|
||||
lockLocations(tracked, pragmaList.sons[i])
|
||||
track(tracked, n.lastSon)
|
||||
setLen(tracked.locked, oldLocked)
|
||||
tracked.currLockLevel = oldLockLevel
|
||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||
nkMacroDef, nkTemplateDef:
|
||||
discard
|
||||
|
|
@ -639,6 +781,16 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
|||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
branch.name.s)
|
||||
if branch.typ.lockLevel > disp.typ.lockLevel:
|
||||
when true:
|
||||
message(branch.info, warnLockLevel,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
else:
|
||||
# XXX make this an error after bigbreak has been released:
|
||||
localError(branch.info,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
|
||||
proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||
var effects = t.n.sons[0]
|
||||
|
|
@ -659,14 +811,13 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
|||
newSeq(effects.sons, effectListLen)
|
||||
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[usesEffects] = newNodeI(nkArgList, s.info)
|
||||
|
||||
t.exc = effects.sons[exceptionEffects]
|
||||
t.tags = effects.sons[tagEffects]
|
||||
t.uses = effects.sons[usesEffects]
|
||||
t.owner = s
|
||||
t.init = @[]
|
||||
t.guards = @[]
|
||||
t.locked = @[]
|
||||
|
||||
proc trackProc*(s: PSym, body: PNode) =
|
||||
var effects = s.typ.n.sons[0]
|
||||
|
|
@ -700,9 +851,17 @@ proc trackProc*(s: PSym, body: PNode) =
|
|||
|
||||
if optThreadAnalysis in gGlobalOptions:
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
if optThreads in gGlobalOptions:
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
else:
|
||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
localError(s.info,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
||||
|
|
@ -711,5 +870,5 @@ proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
|||
var effects = newNode(nkEffectList, n.info)
|
||||
var t: TEffects
|
||||
initEffects(effects, module, t)
|
||||
|
||||
t.isToplevel = true
|
||||
track(t, n)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -29,17 +29,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
|||
of nkIdent: s = lookUp(c, n.sons[0])
|
||||
of nkSym: s = n.sons[0].sym
|
||||
else: illFormedAst(n)
|
||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||
var x = newSymNode(s)
|
||||
x.info = n.info
|
||||
incl(s.flags, sfUsed)
|
||||
n.sons[0] = x
|
||||
suggestSym(x.info, s)
|
||||
styleCheckUse(x.info, s)
|
||||
else:
|
||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||
else:
|
||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||
localError(n.info, errInvalidControlFlowX,
|
||||
renderTree(n, {renderNoComments}))
|
||||
|
||||
|
|
@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
var covered: BiggestInt = 0
|
||||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
var notOrdinal = false
|
||||
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
|
||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
discard
|
||||
notOrdinal = true
|
||||
else:
|
||||
localError(n.info, errSelectorMustBeOfCertainTypes)
|
||||
return
|
||||
|
|
@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
hasElse = true
|
||||
else:
|
||||
illFormedAst(x)
|
||||
if notOrdinal and not hasElse:
|
||||
message(n.info, warnDeprecated,
|
||||
"use 'else: discard'; non-ordinal case without 'else'")
|
||||
if chckCovered:
|
||||
if covered == toCover(n.sons[0].typ):
|
||||
hasElse = true
|
||||
|
|
@ -258,12 +263,13 @@ proc semTry(c: PContext, n: PNode): PNode =
|
|||
n.sons[0] = semExprBranchScope(c, n.sons[0])
|
||||
typ = commonType(typ, n.sons[0].typ)
|
||||
var check = initIntSet()
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var last = sonsLen(n) - 1
|
||||
for i in countup(1, last):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1)
|
||||
var length = sonsLen(a)
|
||||
if a.kind == nkExceptBranch:
|
||||
# XXX what does this do? so that ``except [a, b, c]`` is supported?
|
||||
# so that ``except [a, b, c]`` is supported:
|
||||
if length == 2 and a.sons[0].kind == nkBracket:
|
||||
a.sons[0..0] = a.sons[0].sons
|
||||
length = a.sonsLen
|
||||
|
|
@ -277,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode =
|
|||
a.sons[j].typ = typ
|
||||
if containsOrIncl(check, typ.id):
|
||||
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
||||
elif a.kind != nkFinally:
|
||||
elif a.kind != nkFinally:
|
||||
illFormedAst(n)
|
||||
# last child of an nkExcept/nkFinally branch is a statement:
|
||||
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
||||
typ = commonType(typ, a.sons[length-1].typ)
|
||||
if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
|
||||
else: dec last
|
||||
dec c.p.inTryStmt
|
||||
if isEmptyType(typ) or typ.kind == tyNil:
|
||||
discardCheck(c, n.sons[0])
|
||||
|
|
@ -289,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode =
|
|||
if typ == enforceVoidContext:
|
||||
result.typ = enforceVoidContext
|
||||
else:
|
||||
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
|
||||
n.sons[0] = fitNode(c, typ, n.sons[0])
|
||||
for i in 1..n.len-1:
|
||||
for i in 1..last:
|
||||
var it = n.sons[i]
|
||||
let j = it.len-1
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||
result.typ = typ
|
||||
|
||||
|
||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||
result = fitNode(c, typ, n)
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
|
|
@ -323,6 +331,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
|||
else:
|
||||
result = semIdentWithPragma(c, kind, n, {})
|
||||
suggestSym(n.info, result)
|
||||
styleCheckDef(result)
|
||||
|
||||
proc checkNilable(v: PSym) =
|
||||
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
|
||||
|
|
@ -350,9 +359,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
var def: PNode
|
||||
if a.sons[length-1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
||||
# BUGFIX: ``fitNode`` is needed here!
|
||||
# check type compability between def.typ and typ:
|
||||
if typ != nil: def = fitNode(c, typ, def)
|
||||
if typ != nil:
|
||||
if typ.isMetaType:
|
||||
def = inferWithMetatype(c, typ, def)
|
||||
typ = def.typ
|
||||
else:
|
||||
# BUGFIX: ``fitNode`` is needed here!
|
||||
# check type compability between def.typ and typ
|
||||
def = fitNode(c, typ, def)
|
||||
#changeType(def.skipConv, typ, check=true)
|
||||
else:
|
||||
typ = skipIntLit(def.typ)
|
||||
if typ.kind in {tySequence, tyArray, tySet} and
|
||||
|
|
@ -441,7 +456,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
|||
if typ == nil:
|
||||
localError(a.sons[2].info, errConstExprExpected)
|
||||
continue
|
||||
if not typeAllowed(typ, skConst):
|
||||
if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
|
||||
localError(a.info, errXisNoType, typeToString(typ))
|
||||
continue
|
||||
v.typ = typ
|
||||
|
|
@ -454,153 +469,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
|||
addSon(b, copyTree(def))
|
||||
addSon(result, b)
|
||||
|
||||
type
|
||||
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
|
||||
tupleType: PType # if != nil we're traversing a tuple
|
||||
tupleIndex: int
|
||||
field: PSym
|
||||
replaceByFieldName: bool
|
||||
|
||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
||||
of nkIdent:
|
||||
result = n
|
||||
var L = sonsLen(forLoop)
|
||||
if c.replaceByFieldName:
|
||||
if n.ident.id == forLoop[0].ident.id:
|
||||
let fieldName = if c.tupleType.isNil: c.field.name.s
|
||||
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
|
||||
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
|
||||
result = newStrNode(nkStrLit, fieldName)
|
||||
return
|
||||
# other fields:
|
||||
for i in ord(c.replaceByFieldName)..L-3:
|
||||
if n.ident.id == forLoop[i].ident.id:
|
||||
var call = forLoop.sons[L-2]
|
||||
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
|
||||
if c.field.isNil:
|
||||
result = newNodeI(nkBracketExpr, n.info)
|
||||
result.add(tupl)
|
||||
result.add(newIntNode(nkIntLit, c.tupleIndex))
|
||||
else:
|
||||
result = newNodeI(nkDotExpr, n.info)
|
||||
result.add(tupl)
|
||||
result.add(newSymNode(c.field, n.info))
|
||||
break
|
||||
else:
|
||||
if n.kind == nkContinueStmt:
|
||||
localError(n.info, errGenerated,
|
||||
"'continue' not supported in a 'fields' loop")
|
||||
result = copyNode(n)
|
||||
newSons(result, sonsLen(n))
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
|
||||
|
||||
type
|
||||
TFieldsCtx = object
|
||||
c: PContext
|
||||
m: TMagic
|
||||
|
||||
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
|
||||
case typ.kind
|
||||
of nkSym:
|
||||
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
|
||||
fc.field = typ.sym
|
||||
fc.replaceByFieldName = c.m == mFieldPairs
|
||||
openScope(c.c)
|
||||
inc c.c.inUnrolledContext
|
||||
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
||||
father.add(semStmt(c.c, body))
|
||||
dec c.c.inUnrolledContext
|
||||
closeScope(c.c)
|
||||
of nkNilLit: discard
|
||||
of nkRecCase:
|
||||
let L = forLoop.len
|
||||
let call = forLoop.sons[L-2]
|
||||
if call.len > 2:
|
||||
localError(forLoop.info, errGenerated,
|
||||
"parallel 'fields' iterator does not work for 'case' objects")
|
||||
return
|
||||
# iterate over the selector:
|
||||
semForObjectFields(c, typ[0], forLoop, father)
|
||||
# we need to generate a case statement:
|
||||
var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
|
||||
# generate selector:
|
||||
var access = newNodeI(nkDotExpr, forLoop.info, 2)
|
||||
access.sons[0] = call.sons[1]
|
||||
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
|
||||
caseStmt.add(semExprWithType(c.c, access))
|
||||
# copy the branches over, but replace the fields with the for loop body:
|
||||
for i in 1 .. <typ.len:
|
||||
var branch = copyTree(typ[i])
|
||||
let L = branch.len
|
||||
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
|
||||
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
|
||||
caseStmt.add(branch)
|
||||
father.add(caseStmt)
|
||||
of nkRecList:
|
||||
for t in items(typ): semForObjectFields(c, t, forLoop, father)
|
||||
else:
|
||||
illFormedAst(typ)
|
||||
|
||||
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
# so that 'break' etc. work as expected, we produce
|
||||
# a 'while true: stmt; break' loop ...
|
||||
result = newNodeI(nkWhileStmt, n.info, 2)
|
||||
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
|
||||
if trueSymbol == nil:
|
||||
localError(n.info, errSystemNeeds, "true")
|
||||
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
|
||||
trueSymbol.typ = getSysType(tyBool)
|
||||
|
||||
result.sons[0] = newSymNode(trueSymbol, n.info)
|
||||
var stmts = newNodeI(nkStmtList, n.info)
|
||||
result.sons[1] = stmts
|
||||
|
||||
var length = sonsLen(n)
|
||||
var call = n.sons[length-2]
|
||||
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
||||
localError(n.info, errWrongNumberOfVariables)
|
||||
return result
|
||||
|
||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
|
||||
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
||||
localError(n.info, errGenerated, "no object or tuple type")
|
||||
return result
|
||||
for i in 1..call.len-1:
|
||||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
|
||||
if not sameType(tupleTypeA, tupleTypeB):
|
||||
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
|
||||
|
||||
inc(c.p.nestedLoopCounter)
|
||||
if tupleTypeA.kind == tyTuple:
|
||||
var loopBody = n.sons[length-1]
|
||||
for i in 0..sonsLen(tupleTypeA)-1:
|
||||
openScope(c)
|
||||
var fc: TFieldInstCtx
|
||||
fc.tupleType = tupleTypeA
|
||||
fc.tupleIndex = i
|
||||
fc.replaceByFieldName = m == mFieldPairs
|
||||
var body = instFieldLoopBody(fc, loopBody, n)
|
||||
inc c.inUnrolledContext
|
||||
stmts.add(semStmt(c, body))
|
||||
dec c.inUnrolledContext
|
||||
closeScope(c)
|
||||
else:
|
||||
var fc: TFieldsCtx
|
||||
fc.m = m
|
||||
fc.c = c
|
||||
semForObjectFields(fc, tupleTypeA.n, n, stmts)
|
||||
dec(c.p.nestedLoopCounter)
|
||||
# for TR macros this 'while true: ...; break' loop is pretty bad, so
|
||||
# we avoid it now if we can:
|
||||
if hasSonWith(stmts, nkBreakStmt):
|
||||
var b = newNodeI(nkBreakStmt, n.info)
|
||||
b.add(ast.emptyNode)
|
||||
stmts.add(b)
|
||||
else:
|
||||
result = stmts
|
||||
include semfields
|
||||
|
||||
proc addForVarDecl(c: PContext, v: PSym) =
|
||||
if warnShadowIdent in gNotes:
|
||||
|
|
@ -614,6 +483,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
|
|||
proc symForVar(c: PContext, n: PNode): PSym =
|
||||
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
|
||||
result = newSymG(skForVar, m, c)
|
||||
styleCheckDef(result)
|
||||
|
||||
proc semForVars(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
|
|
@ -906,7 +776,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
|||
if it.kind == nkExprColonExpr:
|
||||
# pass pragma argument to the macro too:
|
||||
x.add(it.sons[1])
|
||||
x.add(newProcNode(nkDo, prc.info, prc))
|
||||
x.add(prc)
|
||||
# recursion assures that this works for multiple macro annotations too:
|
||||
return semStmt(c, x)
|
||||
|
||||
|
|
@ -934,6 +804,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
gp = newNodeI(nkGenericParams, n.info)
|
||||
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
#if n.kind == nkDo and not experimentalMode(c):
|
||||
# localError(n.sons[paramsPos].info,
|
||||
# "use the {.experimental.} pragma to enable 'do' with parameters")
|
||||
semParamList(c, n.sons[paramsPos], gp, s)
|
||||
# paramsTypeCheck(c, s.typ)
|
||||
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
|
||||
|
|
@ -1014,14 +887,21 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
|||
|
||||
proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
case s.name.s.normalize
|
||||
of "destroy": doDestructorStuff(c, s, n)
|
||||
of "destroy":
|
||||
doDestructorStuff(c, s, n)
|
||||
if not experimentalMode(c):
|
||||
localError n.info, "use the {.experimental.} pragma to enable destructors"
|
||||
of "deepcopy":
|
||||
if s.typ.len == 2 and
|
||||
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
|
||||
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||
# Note: we store the deepCopy in the base of the pointer to mitigate
|
||||
# the problem that pointers are structural types:
|
||||
let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||
while true:
|
||||
if t.kind == tyGenericBody: t = t.lastSon
|
||||
elif t.kind == tyGenericInvokation: t = t.sons[0]
|
||||
else: break
|
||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||
if t.deepCopy.isNil: t.deepCopy = s
|
||||
else:
|
||||
|
|
@ -1036,6 +916,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
|||
of "=": discard
|
||||
else: localError(n.info, errGenerated,
|
||||
"'destroy' or 'deepCopy' expected for 'override'")
|
||||
incl(s.flags, sfUsed)
|
||||
|
||||
type
|
||||
TProcCompilationSteps = enum
|
||||
|
|
@ -1128,7 +1009,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
pragma(c, s, n.sons[pragmasPos], validPragmas)
|
||||
else:
|
||||
implicitPragmas(c, s, n, validPragmas)
|
||||
else:
|
||||
else:
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
||||
if sfForward notin proto.flags:
|
||||
|
|
@ -1292,9 +1173,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
|||
let pragmaList = n.sons[0]
|
||||
pragma(c, nil, pragmaList, exprPragmas)
|
||||
result = semExpr(c, n.sons[1])
|
||||
n.sons[1] = result
|
||||
for i in 0 .. <pragmaList.len:
|
||||
if whichPragma(pragmaList.sons[i]) == wLine:
|
||||
setLine(result, pragmaList.sons[i].info)
|
||||
case whichPragma(pragmaList.sons[i])
|
||||
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||
of wLocks:
|
||||
result = n
|
||||
result.typ = n.sons[1].typ
|
||||
else: discard
|
||||
|
||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||
let a = semStmt(c, n.sons[0])
|
||||
|
|
@ -1340,8 +1226,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# nkNilLit, nkEmpty}:
|
||||
# dec last
|
||||
for i in countup(0, length - 1):
|
||||
case n.sons[i].kind
|
||||
of nkFinally, nkExceptBranch:
|
||||
let k = n.sons[i].kind
|
||||
case k
|
||||
of nkFinally, nkExceptBranch, nkDefer:
|
||||
# stand-alone finally and except blocks are
|
||||
# transformed into regular try blocks:
|
||||
#
|
||||
|
|
@ -1350,14 +1237,27 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# ... | ...
|
||||
# | finally:
|
||||
# | fclose(f)
|
||||
var deferPart: PNode
|
||||
if k == nkDefer:
|
||||
deferPart = newNodeI(nkFinally, n.sons[i].info)
|
||||
deferPart.add n.sons[i].sons[0]
|
||||
elif k == nkFinally:
|
||||
message(n.info, warnDeprecated,
|
||||
"use 'defer'; standalone 'finally'")
|
||||
deferPart = n.sons[i]
|
||||
else:
|
||||
message(n.info, warnDeprecated,
|
||||
"use an explicit 'try'; standalone 'except'")
|
||||
deferPart = n.sons[i]
|
||||
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||
var body = newNodeI(nkStmtList, n.sons[i].info)
|
||||
if i < n.sonsLen - 1:
|
||||
body.sons = n.sons[(i+1)..(-1)]
|
||||
tryStmt.addSon(body)
|
||||
tryStmt.addSon(n.sons[i])
|
||||
tryStmt.addSon(deferPart)
|
||||
n.sons[i] = semTry(c, tryStmt)
|
||||
n.sons.setLen(i+1)
|
||||
n.typ = n.sons[i].typ
|
||||
return
|
||||
else:
|
||||
n.sons[i] = semExpr(c, n.sons[i])
|
||||
|
|
@ -1393,11 +1293,16 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
else: discard
|
||||
if result.len == 1:
|
||||
result = result.sons[0]
|
||||
when defined(nimfix):
|
||||
if result.kind == nkCommentStmt and not result.comment.isNil and
|
||||
not (result.comment[0] == '#' and result.comment[1] == '#'):
|
||||
# it is an old-style comment statement: we replace it with 'discard ""':
|
||||
prettybase.replaceComment(result.info)
|
||||
when false:
|
||||
# a statement list (s; e) has the type 'e':
|
||||
if result.kind == nkStmtList and result.len > 0:
|
||||
var lastStmt = lastSon(result)
|
||||
if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt):
|
||||
if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
|
||||
result.typ = lastStmt.typ
|
||||
#localError(lastStmt.info, errGenerated,
|
||||
# "Last expression must be explicitly returned if it " &
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -63,7 +63,8 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
|||
else:
|
||||
# semantic checking requires a type; ``fitNode`` deals with it
|
||||
# appropriately
|
||||
let kind = if r == scClosed: nkClosedSymChoice else: nkOpenSymChoice
|
||||
let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
|
||||
else: nkOpenSymChoice
|
||||
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
|
||||
a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
|
|
@ -71,7 +72,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
|||
addSon(result, newSymNode(a, n.info))
|
||||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
for i in 0 .. < n.len:
|
||||
var a = n.sons[i]
|
||||
# If 'a' is an overloaded symbol, we used to use the first symbol
|
||||
|
|
@ -91,7 +92,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
|||
illFormedAst(a)
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode =
|
||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
||||
for i in 0 .. < n.len:
|
||||
toMixin.incl(considerQuotedIdent(n.sons[i]).id)
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
|
@ -106,7 +107,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
|
|||
type
|
||||
TemplCtx {.pure, final.} = object
|
||||
c: PContext
|
||||
toBind, toMixin, toInject: TIntSet
|
||||
toBind, toMixin, toInject: IntSet
|
||||
owner: PSym
|
||||
|
||||
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
|
||||
|
|
@ -146,6 +147,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
|
|||
if s.owner == c.owner and s.kind == skParam:
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
for i in 0 .. <n.safeLen:
|
||||
result.sons[i] = onlyReplaceParams(c, n.sons[i])
|
||||
|
|
@ -183,12 +185,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
|||
if not isTemplParam(c, ident):
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(n.info, local)
|
||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||
else:
|
||||
replaceIdentBySym(n, ident)
|
||||
|
||||
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
incl(s.flags, sfUsed)
|
||||
# we do not call styleCheckUse here, as the identifier is not really
|
||||
# resolved here. We will fixup the used identifiers later.
|
||||
case s.kind
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
|
|
@ -204,7 +209,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
|||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else:
|
||||
result = n
|
||||
else: result = newSymNode(s, n.info)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||
result = n
|
||||
|
|
@ -214,6 +220,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
|||
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
result.sons[i] = semRoutineInTemplName(c, n.sons[i])
|
||||
|
|
@ -228,6 +235,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
|||
var s = newGenSym(k, ident, c)
|
||||
s.ast = n
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(n.info, s)
|
||||
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
||||
else:
|
||||
n.sons[namePos] = ident
|
||||
|
|
@ -261,6 +269,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
|||
if s.owner == c.owner and s.kind == skParam:
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
elif contains(c.toBind, s.id):
|
||||
result = symChoice(c.c, n, s, scClosed)
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
|
|
@ -270,6 +279,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
|||
# var yz: T
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
else:
|
||||
result = semTemplSymbol(c.c, n, s)
|
||||
of nkBind:
|
||||
|
|
@ -322,6 +332,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
|||
# labels are always 'gensym'ed:
|
||||
let s = newGenSym(skLabel, n.sons[0], c)
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
n.sons[1] = semTemplBody(c, n.sons[1])
|
||||
closeScope(c)
|
||||
|
|
@ -456,6 +467,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
|||
incl(s.flags, sfGlobal)
|
||||
else:
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
||||
styleCheckDef(s)
|
||||
# check parameter list:
|
||||
s.scope = c.currentScope
|
||||
pushOwner(s)
|
||||
|
|
@ -527,6 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
|||
# semtypes.addParamOrResult). Within the pattern we have to ensure
|
||||
# to use the param with the proper type though:
|
||||
incl(s.flags, sfUsed)
|
||||
styleCheckUse(n.info, s)
|
||||
let x = c.owner.typ.n.sons[s.position+1].sym
|
||||
assert x.name == s.name
|
||||
result = newSymNode(x, n.info)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -82,6 +82,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
|||
incl(e.flags, sfExported)
|
||||
if not isPure: strTableAdd(c.module.tab, e)
|
||||
addSon(result.n, newSymNode(e))
|
||||
styleCheckDef(e)
|
||||
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
|
||||
inc(counter)
|
||||
if not hasNull: incl(result.flags, tfNeedsInit)
|
||||
|
|
@ -92,7 +93,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
|||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
if base.kind == tyGenericInst: base = lastSon(base)
|
||||
if base.kind != tyGenericParam:
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif lengthOrd(base) > MaxSetElements:
|
||||
|
|
@ -169,9 +170,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
|||
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
||||
|
||||
var rangeT: array[2, PType]
|
||||
for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||
for i in 0..1:
|
||||
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||
|
||||
if not sameType(rangeT[0], rangeT[1]):
|
||||
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
|
||||
localError(n.info, errPureTypeMismatch)
|
||||
elif not rangeT[0].isOrdinalType:
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
|
|
@ -279,9 +281,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
|||
if n.kind == nkSym:
|
||||
result = n.sym
|
||||
else:
|
||||
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
when defined(nimfix):
|
||||
result = pickSym(c, n, skType)
|
||||
if result.isNil:
|
||||
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
else:
|
||||
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if result != nil:
|
||||
markUsed(n.info, result)
|
||||
styleCheckUse(n.info, result)
|
||||
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
||||
# This is a typedesc param. is it already bound?
|
||||
# it's not bound when it's used multiple times in the
|
||||
|
|
@ -358,7 +366,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
|||
else:
|
||||
addSon(result.n, newSymNode(field))
|
||||
addSonSkipIntLit(result, typ)
|
||||
if gCmd == cmdPretty: checkDef(a.sons[j], field)
|
||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
|
|
@ -378,13 +386,13 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
|||
else:
|
||||
result = newSymG(kind, n, c)
|
||||
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
if n.kind == nkPragmaExpr:
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
if n.kind == nkPragmaExpr:
|
||||
checkSonsLen(n, 2)
|
||||
result = semIdentVis(c, kind, n.sons[0], allowed)
|
||||
case kind
|
||||
of skType:
|
||||
of skType:
|
||||
# process pragmas later, because result.typ has not been set yet
|
||||
discard
|
||||
of skField: pragma(c, result, n.sons[1], fieldPragmas)
|
||||
|
|
@ -394,8 +402,8 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
|||
else: discard
|
||||
else:
|
||||
result = semIdentVis(c, kind, n, allowed)
|
||||
if gCmd == cmdPretty: checkDef(n, result)
|
||||
|
||||
if gCmd == cmdPretty: styleCheckDef(n.info, result)
|
||||
|
||||
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
||||
let ex = t[branchIndex][currentEx].skipConv
|
||||
for i in countup(1, branchIndex):
|
||||
|
|
@ -461,9 +469,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
|||
swap(branch.sons[L-2], branch.sons[L-1])
|
||||
checkForOverlap(c, t, i, branchIndex)
|
||||
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType)
|
||||
proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType) =
|
||||
var a = copyNode(n)
|
||||
checkMinSonsLen(n, 2)
|
||||
|
|
@ -498,7 +506,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
|||
localError(a.info, errNotAllCasesCovered)
|
||||
addSon(father, a)
|
||||
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
|
|
@ -524,7 +532,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
|||
else: illFormedAst(n)
|
||||
if c.inGenericContext > 0:
|
||||
# use a new check intset here for each branch:
|
||||
var newCheck: TIntSet
|
||||
var newCheck: IntSet
|
||||
assign(newCheck, check)
|
||||
var newPos = pos
|
||||
var newf = newNodeI(nkRecList, n.info)
|
||||
|
|
@ -574,11 +582,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
|||
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
|
||||
if a.kind == nkEmpty: addSon(father, newSymNode(f))
|
||||
else: addSon(a, newSymNode(f))
|
||||
styleCheckDef(f)
|
||||
if a.kind != nkEmpty: addSon(father, a)
|
||||
of nkEmpty: discard
|
||||
else: illFormedAst(n)
|
||||
|
||||
proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
|
||||
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
n: PNode) =
|
||||
case n.kind
|
||||
of nkRecCase:
|
||||
|
|
@ -597,7 +606,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
|
|||
inc(pos)
|
||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||
|
||||
proc addInheritedFields(c: PContext, check: var TIntSet, pos: var int,
|
||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
obj: PType) =
|
||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||
addInheritedFields(c, check, pos, obj.sons[0])
|
||||
|
|
@ -814,10 +823,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
for i in 1 .. <paramType.sonsLen:
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
|
||||
let expanded = instGenericContainer(c, info, paramType,
|
||||
allowMetaTypes = true)
|
||||
result = liftingWalk(expanded, true)
|
||||
when false:
|
||||
let expanded = instGenericContainer(c, info, paramType,
|
||||
allowMetaTypes = true)
|
||||
result = liftingWalk(expanded, true)
|
||||
|
||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||
|
|
@ -828,6 +837,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
|
||||
of tyGenericParam:
|
||||
markUsed(info, paramType.sym)
|
||||
styleCheckUse(info, paramType.sym)
|
||||
if tfWildcard in paramType.flags:
|
||||
paramType.flags.excl tfWildcard
|
||||
paramType.sym.kind = skType
|
||||
|
|
@ -844,10 +854,12 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
|||
result = semTypeNode(c, n, nil)
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType, kind: TSymKind): PType =
|
||||
prev: PType, kind: TSymKind; isType=false): PType =
|
||||
# for historical reasons (code grows) this is invoked for parameter
|
||||
# lists too and then 'isType' is false.
|
||||
var
|
||||
res: PNode
|
||||
cl: TIntSet
|
||||
cl: IntSet
|
||||
checkMinSonsLen(n, 1)
|
||||
result = newOrPrevType(tyProc, prev, c)
|
||||
result.callConv = lastOptionEntry(c).defaultCC
|
||||
|
|
@ -893,7 +905,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
if not containsGenericType(typ):
|
||||
def = fitNode(c, typ, def)
|
||||
if not (hasType or hasDefault):
|
||||
if not hasType and not hasDefault:
|
||||
if isType: localError(a.info, "':' expected")
|
||||
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
|
||||
typ = newTypeS(tdef, c)
|
||||
|
||||
|
|
@ -913,29 +926,32 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
addSon(result.n, newSymNode(arg))
|
||||
rawAddSon(result, finalType)
|
||||
addParamOrResult(c, arg, kind)
|
||||
if gCmd == cmdPretty: checkDef(a.sons[j], arg)
|
||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
|
||||
|
||||
var r: PType
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
r = semTypeNode(c, n.sons[0], nil)
|
||||
elif kind == skIterator:
|
||||
# XXX This is special magic we should likely get rid of
|
||||
r = newTypeS(tyAnything, c)
|
||||
|
||||
if r != nil:
|
||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||
# compiler only checks for 'nil':
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
||||
n.sons[0].info)
|
||||
if lifted != nil: r = lifted
|
||||
r.flags.incl tfRetType
|
||||
r = skipIntLit(r)
|
||||
if kind == skIterator:
|
||||
# see tchainediterators
|
||||
# in cases like iterator foo(it: iterator): type(it)
|
||||
# we don't need to change the return type to iter[T]
|
||||
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
if r.kind != tyExpr:
|
||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
||||
n.sons[0].info)
|
||||
if lifted != nil: r = lifted
|
||||
r.flags.incl tfRetType
|
||||
r = skipIntLit(r)
|
||||
if kind == skIterator:
|
||||
# see tchainediterators
|
||||
# in cases like iterator foo(it: iterator): type(it)
|
||||
# we don't need to change the return type to iter[T]
|
||||
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
||||
result.sons[0] = r
|
||||
res.typ = r
|
||||
|
||||
|
|
@ -1059,7 +1075,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
|
|||
prev: PType, kind: TSymKind): PType =
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
result = semProcTypeNode(c, n.sons[0], nil, prev, kind)
|
||||
result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
|
||||
# dummy symbol for `pragma`:
|
||||
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
|
||||
s.typ = result
|
||||
|
|
@ -1188,6 +1204,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
assignType(prev, t)
|
||||
result = prev
|
||||
markUsed(n.info, n.sym)
|
||||
styleCheckUse(n.info, n.sym)
|
||||
else:
|
||||
if n.sym.kind != skError: localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
|
@ -1234,7 +1251,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
|
||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||
m.typ.kind = kind
|
||||
m.typ.align = size
|
||||
m.typ.align = size.int16
|
||||
m.typ.size = size
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
|
|
@ -1332,6 +1349,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
|||
if def.typ.kind != tyTypeDesc:
|
||||
typ = newTypeWithSons(c, tyStatic, @[def.typ])
|
||||
else:
|
||||
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
|
||||
# from manyloc/named_argument_bug/triengine:
|
||||
def.typ = def.typ.skipTypes({tyTypeDesc})
|
||||
if not containsGenericType(def.typ):
|
||||
def = fitNode(c, typ, def)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -216,7 +216,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
|||
result.typ = replaceTypeVarsT(cl, s.typ)
|
||||
result.ast = replaceTypeVarsN(cl, s.ast)
|
||||
|
||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = PType(idTableGet(cl.typeMap, t))
|
||||
if result == nil:
|
||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||
|
|
@ -291,16 +291,24 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
|||
|
||||
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||
result.flags = result.flags + newbody.flags
|
||||
newbody.callConv = body.callConv
|
||||
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||
# This is actually wrong: tgeneric_closure fails with this line:
|
||||
#newbody.callConv = body.callConv
|
||||
# This type may be a generic alias and we want to resolve it here.
|
||||
# One step is enough, because the recursive nature of
|
||||
# handleGenericInvokation will handle the alias-to-alias-to-alias case
|
||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
# don't deal with '(): void':
|
||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||
t.sons[0] = nil
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -25,39 +25,17 @@ var
|
|||
lastCaasCmd* = ""
|
||||
# in caas mode, the list of defines and options will be given at start-up?
|
||||
# it's enough to check that the previous compilation command is the same?
|
||||
arguments* = ""
|
||||
# the arguments to be passed to the program that
|
||||
# should be run
|
||||
|
||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||
var p = parseopt.initOptParser(cmd)
|
||||
var argsCount = 0
|
||||
while true:
|
||||
while true:
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption:
|
||||
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
||||
# we fix this here
|
||||
var bracketLe = strutils.find(p.key, '[')
|
||||
if bracketLe >= 0:
|
||||
var key = substr(p.key, 0, bracketLe - 1)
|
||||
var val = substr(p.key, bracketLe + 1) & ':' & p.val
|
||||
processSwitch(key, val, pass, gCmdLineInfo)
|
||||
else:
|
||||
processSwitch(p.key, p.val, pass, gCmdLineInfo)
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption: processSwitch(pass, p)
|
||||
of cmdArgument:
|
||||
if argsCount == 0:
|
||||
options.command = p.key
|
||||
else:
|
||||
if pass == passCmd1: options.commandArgs.add p.key
|
||||
if argsCount == 1:
|
||||
# support UNIX style filenames anywhere for portable build scripts:
|
||||
options.gProjectName = unixToNativePath(p.key)
|
||||
arguments = cmdLineRest(p)
|
||||
break
|
||||
inc argsCount
|
||||
|
||||
if processArgument(pass, p, argsCount): break
|
||||
if pass == passCmd2:
|
||||
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
|
||||
rawMessage(errArgsNeedRunOption, [])
|
||||
|
|
@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) =
|
|||
of "tcp", "":
|
||||
when useCaas:
|
||||
var server = socket()
|
||||
if server == invalidSocket: osError(osLastError())
|
||||
if server == invalidSocket: raiseOSError(osLastError())
|
||||
let p = getConfigVar("server.port")
|
||||
let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
|
||||
let port = if p.len > 0: parseInt(p).Port else: 6000.Port
|
||||
server.bindAddr(port, getConfigVar("server.address"))
|
||||
var inp = "".TaintedString
|
||||
server.listen()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
import
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees
|
||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
||||
nimfix.pretty
|
||||
|
||||
when not defined(noDocgen):
|
||||
import docgen
|
||||
|
|
@ -21,7 +22,8 @@ type
|
|||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
TCandidate* {.final.} = object
|
||||
CandidateErrors* = seq[PSym]
|
||||
TCandidate* = object
|
||||
c*: PContext
|
||||
exactMatches*: int # also misused to prefer iters over procs
|
||||
genericMatches: int # also misused to prefer constraints
|
||||
|
|
@ -44,7 +46,7 @@ type
|
|||
# a distrinct type
|
||||
typedescMatched: bool
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
errors*: seq[string] # additional clarifications to be displayed to the
|
||||
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||
# user if overload resolution fails
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
|
|
@ -201,16 +203,17 @@ proc writeMatches*(c: TCandidate) =
|
|||
writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||
|
||||
proc argTypeToString(arg: PNode): string =
|
||||
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||
if arg.kind in nkSymChoices:
|
||||
result = typeToString(arg[0].typ)
|
||||
result = typeToString(arg[0].typ, prefer)
|
||||
for i in 1 .. <arg.len:
|
||||
result.add(" | ")
|
||||
result.add typeToString(arg[i].typ)
|
||||
result.add typeToString(arg[i].typ, prefer)
|
||||
else:
|
||||
result = arg.typ.typeToString
|
||||
result = arg.typ.typeToString(prefer)
|
||||
|
||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||
prefer: TPreferedDesc = preferName): string =
|
||||
result = ""
|
||||
for i in countup(startIdx, n.len - 1):
|
||||
var arg = n.sons[i]
|
||||
|
|
@ -226,7 +229,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
|||
arg = c.semOperand(c, n.sons[i])
|
||||
n.sons[i] = arg
|
||||
if arg.typ.kind == tyError: return
|
||||
add(result, argTypeToString(arg))
|
||||
add(result, argTypeToString(arg, prefer))
|
||||
if i != sonsLen(n) - 1: add(result, ", ")
|
||||
|
||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
||||
|
|
@ -239,6 +242,9 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
|||
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
||||
of tyNil:
|
||||
result = nil # what should it be?
|
||||
of tySequence, tySet:
|
||||
if t.sons[0].kind == tyEmpty: result = nil
|
||||
else: result = t
|
||||
of tyGenericParam, tyAnything:
|
||||
result = t
|
||||
while true:
|
||||
|
|
@ -343,7 +349,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
var y = a.n.sons[i].sym
|
||||
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
|
||||
return isNone
|
||||
if x.name.id != y.name.id: return isNone
|
||||
if x.name.id != y.name.id and f.kind != tyTuple: return isNone
|
||||
|
||||
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||
|
|
@ -479,8 +485,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
dummyParam.typ = dummyType
|
||||
addDecl(c, dummyParam)
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false)
|
||||
m.errors = bufferedMsgs
|
||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||
#m.errors = bufferedMsgs
|
||||
clearBufferedMsgs()
|
||||
if checkedBody == nil: return isNone
|
||||
|
||||
|
|
@ -930,6 +936,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
else:
|
||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
if doBind and result notin {isNone, isGeneric}:
|
||||
let concrete = concreteType(c, a)
|
||||
if concrete == nil: return isNone
|
||||
put(c.bindings, f, concrete)
|
||||
else:
|
||||
result = isGeneric
|
||||
|
||||
|
|
@ -1073,6 +1083,11 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
|||
arg: PNode): PNode =
|
||||
# arg.typ can be nil in 'suggest':
|
||||
if isNil(arg.typ): return nil
|
||||
|
||||
# sem'checking for 'echo' needs to be re-entrant:
|
||||
# XXX we will revisit this issue after 0.10.2 is released
|
||||
if f == arg.typ and arg.kind == nkHiddenStdConv: return arg
|
||||
|
||||
var call = newNodeI(nkCall, arg.info)
|
||||
call.add(f.n.copyTree)
|
||||
call.add(arg.copyTree)
|
||||
|
|
@ -1143,8 +1158,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
of isEqual: inc(m.exactMatches)
|
||||
of isNone: discard
|
||||
|
||||
if f.kind == tyStmt and argOrig.kind == nkDo:
|
||||
return argOrig[bodyPos]
|
||||
if f.kind == tyStmt:
|
||||
return arg
|
||||
elif f.kind == tyTypeDesc:
|
||||
return arg
|
||||
elif f.kind == tyStatic:
|
||||
|
|
@ -1272,6 +1287,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
else:
|
||||
# only one valid interpretation found:
|
||||
markUsed(arg.info, arg.sons[best].sym)
|
||||
styleCheckUse(arg.info, arg.sons[best].sym)
|
||||
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
||||
argOrig)
|
||||
|
||||
|
|
@ -1319,7 +1335,7 @@ proc incrIndexType(t: PType) =
|
|||
inc t.sons[0].n.sons[1].intVal
|
||||
|
||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m: var TCandidate, marker: var TIntSet) =
|
||||
m: var TCandidate, marker: var IntSet) =
|
||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||
if not formal.constraint.isNil:
|
||||
if matchNodeKinds(formal.constraint, n):
|
||||
|
|
@ -1480,8 +1496,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
|||
# instantiate generic converters for that
|
||||
result = res != nil
|
||||
|
||||
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
|
||||
procvar.} =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, dc.typ)
|
||||
var f = dc.typ.sons[1]
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
|
||||
else:
|
||||
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
||||
assert sfFromGeneric in result.flags
|
||||
|
||||
include suggest
|
||||
|
||||
when not declared(tests):
|
||||
template tests(s: stmt) {.immediate.} = discard
|
||||
|
||||
tests:
|
||||
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
# included from sigmatch.nim
|
||||
|
||||
import algorithm, sequtils, pretty
|
||||
import algorithm, sequtils
|
||||
|
||||
const
|
||||
sep = '\t'
|
||||
|
|
@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) =
|
|||
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
|
||||
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
||||
suggestSym(info, s)
|
||||
if gCmd == cmdPretty: checkUse(info, s)
|
||||
|
||||
proc useSym*(sym: PSym): PNode =
|
||||
result = newSymNode(sym)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -44,7 +44,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
|
|||
proc parseFile(fileIdx: int32): PNode =
|
||||
var
|
||||
p: TParsers
|
||||
f: TFile
|
||||
f: File
|
||||
let filename = fileIdx.toFullPath
|
||||
if not open(f, filename):
|
||||
rawMessage(errCannotOpenFile, filename)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2014 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -582,7 +582,7 @@ proc getMergeOp(n: PNode): PSym =
|
|||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||
var op2 = getMergeOp(a)
|
||||
let op2 = getMergeOp(a)
|
||||
if op2 != nil and
|
||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
||||
|
|
@ -590,7 +590,7 @@ proc flattenTreeAux(d, a: PNode, op: PSym) =
|
|||
addSon(d, copyTree(a))
|
||||
|
||||
proc flattenTree(root: PNode): PNode =
|
||||
var op = getMergeOp(root)
|
||||
let op = getMergeOp(root)
|
||||
if op != nil:
|
||||
result = copyNode(root)
|
||||
addSon(result, copyTree(root.sons[0]))
|
||||
|
|
@ -600,8 +600,9 @@ proc flattenTree(root: PNode): PNode =
|
|||
|
||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
var n = flattenTree(n)
|
||||
var op = getMergeOp(n)
|
||||
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
|
||||
let op = getMergeOp(n)
|
||||
let magic = getMagic(n)
|
||||
if op != nil and op.magic != mNone and n.len >= 3:
|
||||
result = newTransNode(nkCall, n, 0)
|
||||
add(result, transform(c, n.sons[0]))
|
||||
var j = 1
|
||||
|
|
@ -616,9 +617,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
|||
inc(j)
|
||||
add(result, a.PTransNode)
|
||||
if len(result) == 2: result = result[1]
|
||||
elif getMagic(n) == mNBindSym:
|
||||
elif magic == mNBindSym:
|
||||
# for bindSym(myconst) we MUST NOT perform constant folding:
|
||||
result = n.PTransNode
|
||||
elif magic == mProcCall:
|
||||
# but do not change to its dispatcher:
|
||||
result = transformSons(c, n[1])
|
||||
else:
|
||||
let s = transformSons(c, n).PNode
|
||||
# bugfix: check after 'transformSons' if it's still a method call:
|
||||
|
|
@ -785,8 +789,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
|||
# result = lambdalifting.liftIterator(prc, result)
|
||||
incl(result.flags, nfTransf)
|
||||
when useEffectSystem: trackProc(prc, result)
|
||||
if prc.name.s == "testbody":
|
||||
echo renderTree(result)
|
||||
#if prc.name.s == "testbody":
|
||||
# echo renderTree(result)
|
||||
|
||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
@ -117,7 +117,9 @@ proc isDeepConstExpr*(n: PNode): bool =
|
|||
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
|
||||
for i in 0 .. <n.len:
|
||||
if not isDeepConstExpr(n.sons[i]): return false
|
||||
result = true
|
||||
# XXX once constant objects are supported by the codegen this needs to be
|
||||
# weakened:
|
||||
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
|
||||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue